<commit_before>//==============================================================================
// Raw CellML view widget
//==============================================================================

#include "qscintilla.h"
#include "rawcellmlviewwidget.h"
#include "viewerwidget.h"

//==============================================================================

#include "ui_rawcellmlviewwidget.h"

//==============================================================================

#include <QDesktopWidget>
#include <QFileInfo>
#include <QSplitter>
#include <QTextStream>

//==============================================================================

#include "Qsci/qscilexerxml.h"

//==============================================================================

namespace OpenCOR {
namespace RawCellMLView {

//==============================================================================

RawCellmlViewWidget::RawCellmlViewWidget(QWidget *pParent) :
    Widget(pParent),
    mUi(new Ui::RawCellmlViewWidget),
    mEditors(QMap<QString, QScintillaSupport::QScintilla *>()),
    mEditor(0),
    mViewerHeight(0),
    mEditorHeight(0)
{
    // Set up the UI

    mUi->setupUi(this);

    // Create our vertical splitter

    mVerticalSplitter = new QSplitter(Qt::Vertical, this);

    connect(mVerticalSplitter, SIGNAL(splitterMoved(int,int)),
            this, SLOT(verticalSplitterMoved()));

    // Create a viewer

    mViewer = new Viewer::ViewerWidget(pParent);

    // Populate our vertical splitter and add it to our raw CellML view widget

    mVerticalSplitter->addWidget(mViewer);

    mUi->verticalLayout->addWidget(mVerticalSplitter);
}

//==============================================================================

static const QString SettingsViewerHeight = "ViewerHeight";
static const QString SettingsEditorHeight = "EditorHeight";

//==============================================================================

void RawCellmlViewWidget::loadSettings(QSettings *pSettings)
{
    // Retrieve the viewer's and editor's height
    // Note #1: the viewer's default height is 19% of the desktop's height while
    //          that of the editor is as big as it can be...
    // Note #2: because the editor's default height is much bigger than our raw
    //          CellML view widget's height, the viewer's default height will
    //          effectively be less than 19% of the desktop's height, but that
    //          doesn't matter at all...

    mViewerHeight = pSettings->value(SettingsViewerHeight,
                                     0.19*qApp->desktop()->screenGeometry().height()).toInt();
    mEditorHeight = pSettings->value(SettingsEditorHeight,
                                     qApp->desktop()->screenGeometry().height()).toInt();
}

//==============================================================================

void RawCellmlViewWidget::saveSettings(QSettings *pSettings) const
{
    // Keep track of the viewer's and editor's height
    // Note #1: we must also keep track of the editor's height because when
    //          loading our raw CellML view widget's settings (see above), the
    //          widget doesn't yet have a 'proper' height, so we couldn't simply
    //          assume that the editor's initial height is this widget's height
    //          minus the viewer's initial height, so...
    // Note #2: we rely on mViewerHeight and mEditorHeight rather than directly
    //          calling the height() method of the viewer and of the editor,
    //          respectively since it may happen that the user exits OpenCOR
    //          without ever having switched to the raw CellML view, in which
    //          case we couldn't retrieve the viewer and editor's height which
    //          in turn would result in OpenCOR crashing, so...

    pSettings->setValue(SettingsViewerHeight, mViewerHeight);
    pSettings->setValue(SettingsEditorHeight, mEditorHeight);
}

//==============================================================================

void RawCellmlViewWidget::initialize(const QString &pFileName)
{
    // Retrieve the size of our viewer and current editor, and hide the editor

    bool needInitialSizes = !mEditor;

    int viewerHeight = 0;
    int editorHeight = 0;

    if (mEditor) {
        // An editor is currently available, so retrieve the size of both our
        // viewer and the current editor

        viewerHeight = mViewer->height();
        editorHeight = mEditor->height();

        // Hide the current editor

        mEditor->hide();
    }

    // Retrieve the editor associated with the file name, if any

    mEditor = mEditors.value(pFileName);

    if (!mEditor) {
        // No editor exists for the file name, so create and set up a Scintilla
        // editor with an XML lexer associated to it

        QFile file(pFileName);
        QString fileContents = QString();
        bool fileIsWritable = false;

        if (file.open(QIODevice::ReadOnly|QIODevice::Text)) {
            // We could open the file, so retrieve its contents and whether it
            // can be written to

            fileContents = QTextStream(&file).readAll();
            fileIsWritable = !(QFileInfo(pFileName).isWritable());

            // We are done with the file, so close it

            file.close();
        }

        mEditor = new QScintillaSupport::QScintilla(qobject_cast<QWidget *>(parent()),
                                                    fileContents, fileIsWritable,
                                                    new QsciLexerXML(parent()));

        // Keep track of the editor and add it to our vertical splitter

        mEditors.insert(pFileName, mEditor);

        mVerticalSplitter->addWidget(mEditor);
    }

    // Make sure that the 'new' editor is visible

    mEditor->show();

    // Set the raw CellML view widget's focus proxy to the 'new' editor

    setFocusProxy(mEditor);

    // Adjust our vertical splitter's sizes

    if (needInitialSizes) {
        // We need to initialise our vertical splitter's sizes, so...

        mVerticalSplitter->setSizes(QList<int>() << mViewerHeight
                                                 << mEditorHeight);
    } else {
        // Our vertical splitter's sizes have already been initialised, so set
        // its sizes so that our 'new' editor gets its size set to that of the
        // 'old' editor

        QList<int> newSizes = QList<int>() << viewerHeight;

        for (int i = 1, iMax = mVerticalSplitter->count(); i < iMax; ++i)
            if (dynamic_cast<QScintillaSupport::QScintilla *>(mVerticalSplitter->widget(i)) == mEditor)
                // This is the editor we are after, so...

                newSizes << editorHeight;
            else
                // Not the editor we are after, so...

                newSizes << 0;

        mVerticalSplitter->setSizes(newSizes);
    }
}

//==============================================================================

void RawCellmlViewWidget::verticalSplitterMoved()
{
    // The splitter has moved, so keep track of the viewer and editor's new
    // height

    mViewerHeight = mViewer->height();
    mEditorHeight = mEditor->height();
}

//==============================================================================

}   // namespace RawCellMLView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Slight GUI improvement to our RawCellMLView plugin (#16).<commit_after>//==============================================================================
// Raw CellML view widget
//==============================================================================

#include "coreutils.h"
#include "qscintilla.h"
#include "rawcellmlviewwidget.h"
#include "viewerwidget.h"

//==============================================================================

#include "ui_rawcellmlviewwidget.h"

//==============================================================================

#include <QDesktopWidget>
#include <QFileInfo>
#include <QSplitter>
#include <QTextStream>

//==============================================================================

#include "Qsci/qscilexerxml.h"

//==============================================================================

namespace OpenCOR {
namespace RawCellMLView {

//==============================================================================

RawCellmlViewWidget::RawCellmlViewWidget(QWidget *pParent) :
    Widget(pParent),
    mUi(new Ui::RawCellmlViewWidget),
    mEditors(QMap<QString, QScintillaSupport::QScintilla *>()),
    mEditor(0),
    mViewerHeight(0),
    mEditorHeight(0)
{
    // Set up the UI

    mUi->setupUi(this);

    // Create our vertical splitter

    mVerticalSplitter = new QSplitter(Qt::Vertical, this);

    connect(mVerticalSplitter, SIGNAL(splitterMoved(int,int)),
            this, SLOT(verticalSplitterMoved()));

    // Create a viewer with a real line at the bottom of it

    QWidget *viewerWidget = new QWidget(this);
    QVBoxLayout *viewerVerticalLayout= new QVBoxLayout(viewerWidget);

    viewerVerticalLayout->setContentsMargins(0, 0, 0, 0);
    viewerVerticalLayout->setSpacing(0);

    viewerWidget->setLayout(viewerVerticalLayout);

    mViewer = new Viewer::ViewerWidget(pParent);

    viewerVerticalLayout->addWidget(mViewer);
    viewerVerticalLayout->addWidget(Core::newRealLineWidget(this));

    // Populate our vertical splitter and add it to our raw CellML view widget

    mVerticalSplitter->addWidget(viewerWidget);

    mUi->verticalLayout->addWidget(mVerticalSplitter);
}

//==============================================================================

static const QString SettingsViewerHeight = "ViewerHeight";
static const QString SettingsEditorHeight = "EditorHeight";

//==============================================================================

void RawCellmlViewWidget::loadSettings(QSettings *pSettings)
{
    // Retrieve the viewer's and editor's height
    // Note #1: the viewer's default height is 19% of the desktop's height while
    //          that of the editor is as big as it can be...
    // Note #2: because the editor's default height is much bigger than our raw
    //          CellML view widget's height, the viewer's default height will
    //          effectively be less than 19% of the desktop's height, but that
    //          doesn't matter at all...

    mViewerHeight = pSettings->value(SettingsViewerHeight,
                                     0.19*qApp->desktop()->screenGeometry().height()).toInt();
    mEditorHeight = pSettings->value(SettingsEditorHeight,
                                     qApp->desktop()->screenGeometry().height()).toInt();
}

//==============================================================================

void RawCellmlViewWidget::saveSettings(QSettings *pSettings) const
{
    // Keep track of the viewer's and editor's height
    // Note #1: we must also keep track of the editor's height because when
    //          loading our raw CellML view widget's settings (see above), the
    //          widget doesn't yet have a 'proper' height, so we couldn't simply
    //          assume that the editor's initial height is this widget's height
    //          minus the viewer's initial height, so...
    // Note #2: we rely on mViewerHeight and mEditorHeight rather than directly
    //          calling the height() method of the viewer and of the editor,
    //          respectively since it may happen that the user exits OpenCOR
    //          without ever having switched to the raw CellML view, in which
    //          case we couldn't retrieve the viewer and editor's height which
    //          in turn would result in OpenCOR crashing, so...

    pSettings->setValue(SettingsViewerHeight, mViewerHeight);
    pSettings->setValue(SettingsEditorHeight, mEditorHeight);
}

//==============================================================================

void RawCellmlViewWidget::initialize(const QString &pFileName)
{
    // Retrieve the size of our viewer and current editor, and hide the editor

    bool needInitialSizes = !mEditor;

    int viewerHeight = 0;
    int editorHeight = 0;

    if (mEditor) {
        // An editor is currently available, so retrieve the size of both our
        // viewer and the current editor

        viewerHeight = mViewer->height();
        editorHeight = mEditor->height();

        // Hide the current editor

        mEditor->hide();
    }

    // Retrieve the editor associated with the file name, if any

    mEditor = mEditors.value(pFileName);

    if (!mEditor) {
        // No editor exists for the file name, so create and set up a Scintilla
        // editor with an XML lexer associated to it

        QFile file(pFileName);
        QString fileContents = QString();
        bool fileIsWritable = false;

        if (file.open(QIODevice::ReadOnly|QIODevice::Text)) {
            // We could open the file, so retrieve its contents and whether it
            // can be written to

            fileContents = QTextStream(&file).readAll();
            fileIsWritable = !(QFileInfo(pFileName).isWritable());

            // We are done with the file, so close it

            file.close();
        }

        mEditor = new QScintillaSupport::QScintilla(qobject_cast<QWidget *>(parent()),
                                                    fileContents, fileIsWritable,
                                                    new QsciLexerXML(parent()));

        // Keep track of the editor and add it to our vertical splitter

        mEditors.insert(pFileName, mEditor);

        mVerticalSplitter->addWidget(mEditor);
    }

    // Make sure that the 'new' editor is visible

    mEditor->show();

    // Set the raw CellML view widget's focus proxy to the 'new' editor

    setFocusProxy(mEditor);

    // Adjust our vertical splitter's sizes

    if (needInitialSizes) {
        // We need to initialise our vertical splitter's sizes, so...

        mVerticalSplitter->setSizes(QList<int>() << mViewerHeight
                                                 << mEditorHeight);
    } else {
        // Our vertical splitter's sizes have already been initialised, so set
        // its sizes so that our 'new' editor gets its size set to that of the
        // 'old' editor

        QList<int> newSizes = QList<int>() << viewerHeight;

        for (int i = 1, iMax = mVerticalSplitter->count(); i < iMax; ++i)
            if (dynamic_cast<QScintillaSupport::QScintilla *>(mVerticalSplitter->widget(i)) == mEditor)
                // This is the editor we are after, so...

                newSizes << editorHeight;
            else
                // Not the editor we are after, so...

                newSizes << 0;

        mVerticalSplitter->setSizes(newSizes);
    }
}

//==============================================================================

void RawCellmlViewWidget::verticalSplitterMoved()
{
    // The splitter has moved, so keep track of the viewer and editor's new
    // height

    mViewerHeight = mViewer->height();
    mEditorHeight = mEditor->height();
}

//==============================================================================

}   // namespace RawCellMLView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2012      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "OSRMRunner.h"

#include "MarbleDebug.h"
#include "MarbleLocale.h"
#include "GeoDataDocument.h"
#include "GeoDataPlacemark.h"
#include "GeoDataExtendedData.h"
#include "routing/Maneuver.h"
#include "routing/RouteRequest.h"
#include "TinyWebBrowser.h"

#include <QString>
#include <QVector>
#include <QUrl>
#include <QTime>
#include <QTimer>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QScriptValue>
#include <QScriptEngine>
#include <QScriptValueIterator>

namespace Marble
{

QVector<QPair<GeoDataCoordinates,QString> > OSRMRunner:: m_cachedHints;

QString OSRMRunner:: m_hintChecksum;

OSRMRunner::OSRMRunner( QObject *parent ) :
    RoutingRunner( parent ),
    m_networkAccessManager()
{
    connect( &m_networkAccessManager, SIGNAL(finished(QNetworkReply*)),
             this, SLOT(retrieveData(QNetworkReply*)) );
}

OSRMRunner::~OSRMRunner()
{
    // nothing to do
}

void OSRMRunner::retrieveRoute( const RouteRequest *route )
{
    if ( route->size() < 2 ) {
        return;
    }

    QString url = "http://router.project-osrm.org/viaroute?output=json&instructions=true";
    GeoDataCoordinates::Unit const degree = GeoDataCoordinates::Degree;
    bool appendChecksum = false;
    typedef QPair<GeoDataCoordinates,QString> CachePair;
    QVector<CachePair> newChecksums;
    QString const invalidEntry = "invalid";
    for ( int i=0; i<route->size(); ++i ) {
        GeoDataCoordinates const coordinates = route->at( i );
        append( &url, "loc", QString::number( coordinates.latitude( degree ), 'f', 6 ) + ',' + QString::number( coordinates.longitude( degree ), 'f', 6 ) );
        foreach( const CachePair &hint, m_cachedHints ) {
            if ( hint.first == coordinates && hint.second != invalidEntry && m_hintChecksum != invalidEntry ) {
                append( &url, "hint", hint.second );
                appendChecksum = true;
            }
        }
        newChecksums << CachePair( coordinates, invalidEntry );
    }

    if ( appendChecksum ) {
        append( &url, "checksum", m_hintChecksum );
    }

    m_cachedHints = newChecksums;
    m_hintChecksum = invalidEntry;

    m_request = QNetworkRequest( QUrl( url ) );
    m_request.setRawHeader( "User-Agent", TinyWebBrowser::userAgent( "Browser", "OSRMRunner" ) );

    QEventLoop eventLoop;

    QTimer timer;
    timer.setSingleShot( true );
    timer.setInterval( 15000 );

    connect( &timer, SIGNAL(timeout()),
             &eventLoop, SLOT(quit()));
    connect( this, SIGNAL(routeCalculated(GeoDataDocument*)),
             &eventLoop, SLOT(quit()) );

    // @todo FIXME Must currently be done in the main thread, see bug 257376
    QTimer::singleShot( 0, this, SLOT(get()) );
    timer.start();

    eventLoop.exec();
}

void OSRMRunner::retrieveData( QNetworkReply *reply )
{
    if ( reply->isFinished() ) {
        QByteArray data = reply->readAll();
        reply->deleteLater();
        GeoDataDocument* document = parse( data );

        if ( !document ) {
            mDebug() << "Failed to parse the downloaded route data" << data;
        }

        emit routeCalculated( document );
    }
}

void OSRMRunner::handleError( QNetworkReply::NetworkError error )
{
    mDebug() << " Error when retrieving OSRM route: " << error;
}

void OSRMRunner::get()
{
    QNetworkReply *reply = m_networkAccessManager.get( m_request );
    connect( reply, SIGNAL(error(QNetworkReply::NetworkError)),
             this, SLOT(handleError(QNetworkReply::NetworkError)), Qt::DirectConnection );
}

void OSRMRunner::append(QString *input, const QString &key, const QString &value) const
{
    *input += '&' + key + '=' + value;
}

GeoDataLineString *OSRMRunner::decodePolyline( const QString &geometry ) const
{
    // See https://developers.google.com/maps/documentation/utilities/polylinealgorithm
    GeoDataLineString* lineString = new GeoDataLineString;
    int coordinates[2] = { 0, 0 };
    int const length = geometry.length();
    for( int i=0; i<length; /* increment happens below */ ) {
        for ( int j=0; j<2; ++j ) { // lat and lon
            int block( 0 ), shift( 0 ), result( 0 );
            do {
                block = geometry.at( i++ /* increment for outer loop */ ).toAscii() - 63;
                result |= ( block & 0x1F ) << shift;
                shift += 5;
            } while ( block >= 0x20 );
            coordinates[j] += ( ( result & 1 ) != 0 ? ~( result >> 1 ) : ( result >> 1 ) );
        }
        lineString->append( GeoDataCoordinates( double( coordinates[1] ) / 1E5,
                                                double( coordinates[0] ) / 1E5,
                                                0.0, GeoDataCoordinates::Degree ) );
    }
    return lineString;
}

RoutingInstruction::TurnType OSRMRunner::parseTurnType( const QString &instruction ) const
{
    if ( instruction == "1" ) {
        return RoutingInstruction::Straight;
    } else if ( instruction == "2" ) {
        return RoutingInstruction::SlightRight;
    } else if ( instruction == "3" ) {
        return RoutingInstruction::Right;
    } else if ( instruction == "4" ) {
        return RoutingInstruction::SharpRight;
    } else if ( instruction == "5" ) {
        return RoutingInstruction::TurnAround;
    } else if ( instruction == "6" ) {
        return RoutingInstruction::SharpLeft;
    } else if ( instruction == "7" ) {
        return RoutingInstruction::Left;
    } else if ( instruction == "8" ) {
        return RoutingInstruction::SlightLeft;
    } else if ( instruction == "10" ) {
        return RoutingInstruction::Continue;
    } else if ( instruction.startsWith( QLatin1String( "11-" ) ) ) {
        int const exit = instruction.mid( 3 ).toInt();
        switch ( exit ) {
        case 1: return RoutingInstruction::RoundaboutFirstExit; break;
        case 2: return RoutingInstruction::RoundaboutSecondExit; break;
        case 3: return RoutingInstruction::RoundaboutThirdExit; break;
        default: return RoutingInstruction::RoundaboutExit;
        }
    } else if ( instruction == "12" ) {
        return RoutingInstruction::RoundaboutExit;
    }

    // ignoring ReachViaPoint = 9;
    // ignoring StayOnRoundAbout = 13;
    // ignoring StartAtEndOfStreet = 14;
    // ignoring ReachedYourDestination = 15;

    return RoutingInstruction::Unknown;
}

GeoDataDocument *OSRMRunner::parse( const QByteArray &input )
{
    QScriptEngine engine;
    // Qt requires parentheses around json code
    QScriptValue const data = engine.evaluate( '(' + QString::fromUtf8( input ) + ')' );

    GeoDataDocument* result = 0;
    GeoDataLineString* routeWaypoints = 0;
    if ( data.property( "route_geometry" ).isString() ) {
        result = new GeoDataDocument();
        result->setName( "Open Source Routing Machine" );
        GeoDataPlacemark* routePlacemark = new GeoDataPlacemark;
        routePlacemark->setName( "Route" );
        routeWaypoints = decodePolyline( data.property( "route_geometry" ).toString() );
        routePlacemark->setGeometry( routeWaypoints );

        QString name = "%1 %2 (OSRM)";
        QString unit = QLatin1String( "m" );
        qreal length = routeWaypoints->length( EARTH_RADIUS );
        if (length >= 1000) {
            length /= 1000.0;
            unit = "km";
        }
        result->setName( name.arg( length, 0, 'f', 1 ).arg( unit ) );
        result->append( routePlacemark );
    }

    if ( result && routeWaypoints && data.property( "route_instructions" ).isArray() ) {
        bool first = true;
        QScriptValueIterator iterator( data.property( "route_instructions" ) );
        GeoDataPlacemark* instruction = new GeoDataPlacemark;
        int lastWaypointIndex = 0;
        while ( iterator.hasNext() ) {
            iterator.next();
            QVariantList details = iterator.value().toVariant().toList();
            if ( details.size() > 7 ) {
                QString const text = details.at( 0 ).toString();
                QString const road = details.at( 1 ).toString();
                int const waypointIndex = details.at( 3 ).toInt();

                if ( waypointIndex < routeWaypoints->size() ) {
                    if ( iterator.hasNext() ) {
                        GeoDataLineString *lineString = new GeoDataLineString;
                        for ( int i=lastWaypointIndex; i<=waypointIndex; ++i ) {
                            lineString->append(routeWaypoints->at( i ) );
                        }
                        instruction->setGeometry( lineString );
                        result->append( instruction );
                        instruction = new GeoDataPlacemark;
                    }
                    lastWaypointIndex = waypointIndex;
                    GeoDataExtendedData extendedData;
                    GeoDataData turnTypeData;
                    turnTypeData.setName( "turnType" );
                    RoutingInstruction::TurnType turnType = parseTurnType( text );
                    turnTypeData.setValue( turnType );
                    extendedData.addValue( turnTypeData );
                    if (!road.isEmpty()) {
                        GeoDataData roadName;
                        roadName.setName( "roadName" );
                        roadName.setValue( road );
                        extendedData.addValue( roadName );
                    }

                    if ( first ) {
                        turnType = RoutingInstruction::Continue;
                        first = false;
                    }

                    if ( turnType == RoutingInstruction::Unknown ) {
                        instruction->setName( text );
                    } else {
                        instruction->setName( RoutingInstruction::generateRoadInstruction( turnType, road ) );
                    }
                    instruction->setExtendedData( extendedData );

                    if ( !iterator.hasNext() && lastWaypointIndex > 0 ) {
                        GeoDataLineString *lineString = new GeoDataLineString;
                        for ( int i=lastWaypointIndex; i<waypointIndex; ++i ) {
                            lineString->append(routeWaypoints->at( i ) );
                        }
                        instruction->setGeometry( lineString );
                        result->append( instruction );
                    }
                }
            }
        }
    }

    if ( data.property( "hint_data" ).isValid() ) {
        QVariantList hints = data.property( "hint_data" ).property( "locations" ).toVariant().toList();
        if ( hints.size() == m_cachedHints.size() ) {
            for ( int i=0; i<m_cachedHints.size(); ++i ) {
                m_cachedHints[i].second = hints[i].toString();
            }
        }

        m_hintChecksum = data.property( "hint_data" ).property( "checksum" ).toString();
    }

    return result;
}

} // namespace Marble

#include "OSRMRunner.moc"
<commit_msg>Fix polyline decoding.<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2012      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "OSRMRunner.h"

#include "MarbleDebug.h"
#include "MarbleLocale.h"
#include "GeoDataDocument.h"
#include "GeoDataPlacemark.h"
#include "GeoDataExtendedData.h"
#include "routing/Maneuver.h"
#include "routing/RouteRequest.h"
#include "TinyWebBrowser.h"

#include <QString>
#include <QVector>
#include <QUrl>
#include <QTime>
#include <QTimer>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QScriptValue>
#include <QScriptEngine>
#include <QScriptValueIterator>

namespace Marble
{

QVector<QPair<GeoDataCoordinates,QString> > OSRMRunner:: m_cachedHints;

QString OSRMRunner:: m_hintChecksum;

OSRMRunner::OSRMRunner( QObject *parent ) :
    RoutingRunner( parent ),
    m_networkAccessManager()
{
    connect( &m_networkAccessManager, SIGNAL(finished(QNetworkReply*)),
             this, SLOT(retrieveData(QNetworkReply*)) );
}

OSRMRunner::~OSRMRunner()
{
    // nothing to do
}

void OSRMRunner::retrieveRoute( const RouteRequest *route )
{
    if ( route->size() < 2 ) {
        return;
    }

    QString url = "http://router.project-osrm.org/viaroute?output=json&instructions=true";
    GeoDataCoordinates::Unit const degree = GeoDataCoordinates::Degree;
    bool appendChecksum = false;
    typedef QPair<GeoDataCoordinates,QString> CachePair;
    QVector<CachePair> newChecksums;
    QString const invalidEntry = "invalid";
    for ( int i=0; i<route->size(); ++i ) {
        GeoDataCoordinates const coordinates = route->at( i );
        append( &url, "loc", QString::number( coordinates.latitude( degree ), 'f', 6 ) + ',' + QString::number( coordinates.longitude( degree ), 'f', 6 ) );
        foreach( const CachePair &hint, m_cachedHints ) {
            if ( hint.first == coordinates && hint.second != invalidEntry && m_hintChecksum != invalidEntry ) {
                append( &url, "hint", hint.second );
                appendChecksum = true;
            }
        }
        newChecksums << CachePair( coordinates, invalidEntry );
    }

    if ( appendChecksum ) {
        append( &url, "checksum", m_hintChecksum );
    }

    m_cachedHints = newChecksums;
    m_hintChecksum = invalidEntry;

    m_request = QNetworkRequest( QUrl( url ) );
    m_request.setRawHeader( "User-Agent", TinyWebBrowser::userAgent( "Browser", "OSRMRunner" ) );

    QEventLoop eventLoop;

    QTimer timer;
    timer.setSingleShot( true );
    timer.setInterval( 15000 );

    connect( &timer, SIGNAL(timeout()),
             &eventLoop, SLOT(quit()));
    connect( this, SIGNAL(routeCalculated(GeoDataDocument*)),
             &eventLoop, SLOT(quit()) );

    // @todo FIXME Must currently be done in the main thread, see bug 257376
    QTimer::singleShot( 0, this, SLOT(get()) );
    timer.start();

    eventLoop.exec();
}

void OSRMRunner::retrieveData( QNetworkReply *reply )
{
    if ( reply->isFinished() ) {
        QByteArray data = reply->readAll();
        reply->deleteLater();
        GeoDataDocument* document = parse( data );

        if ( !document ) {
            mDebug() << "Failed to parse the downloaded route data" << data;
        }

        emit routeCalculated( document );
    }
}

void OSRMRunner::handleError( QNetworkReply::NetworkError error )
{
    mDebug() << " Error when retrieving OSRM route: " << error;
}

void OSRMRunner::get()
{
    QNetworkReply *reply = m_networkAccessManager.get( m_request );
    connect( reply, SIGNAL(error(QNetworkReply::NetworkError)),
             this, SLOT(handleError(QNetworkReply::NetworkError)), Qt::DirectConnection );
}

void OSRMRunner::append(QString *input, const QString &key, const QString &value) const
{
    *input += '&' + key + '=' + value;
}

GeoDataLineString *OSRMRunner::decodePolyline( const QString &geometry ) const
{
    // See https://developers.google.com/maps/documentation/utilities/polylinealgorithm
    GeoDataLineString* lineString = new GeoDataLineString;
    int coordinates[2] = { 0, 0 };
    int const length = geometry.length();
    for( int i=0; i<length; /* increment happens below */ ) {
        for ( int j=0; j<2; ++j ) { // lat and lon
            int block( 0 ), shift( 0 ), result( 0 );
            do {
                block = geometry.at( i++ /* increment for outer loop */ ).toAscii() - 63;
                result |= ( block & 0x1F ) << shift;
                shift += 5;
            } while ( block >= 0x20 );
            coordinates[j] += ( ( result & 1 ) != 0 ? ~( result >> 1 ) : ( result >> 1 ) );
        }
        lineString->append( GeoDataCoordinates( double( coordinates[1] ) / 1E6,
                                                double( coordinates[0] ) / 1E6,
                                                0.0, GeoDataCoordinates::Degree ) );
    }
    return lineString;
}

RoutingInstruction::TurnType OSRMRunner::parseTurnType( const QString &instruction ) const
{
    if ( instruction == "1" ) {
        return RoutingInstruction::Straight;
    } else if ( instruction == "2" ) {
        return RoutingInstruction::SlightRight;
    } else if ( instruction == "3" ) {
        return RoutingInstruction::Right;
    } else if ( instruction == "4" ) {
        return RoutingInstruction::SharpRight;
    } else if ( instruction == "5" ) {
        return RoutingInstruction::TurnAround;
    } else if ( instruction == "6" ) {
        return RoutingInstruction::SharpLeft;
    } else if ( instruction == "7" ) {
        return RoutingInstruction::Left;
    } else if ( instruction == "8" ) {
        return RoutingInstruction::SlightLeft;
    } else if ( instruction == "10" ) {
        return RoutingInstruction::Continue;
    } else if ( instruction.startsWith( QLatin1String( "11-" ) ) ) {
        int const exit = instruction.mid( 3 ).toInt();
        switch ( exit ) {
        case 1: return RoutingInstruction::RoundaboutFirstExit; break;
        case 2: return RoutingInstruction::RoundaboutSecondExit; break;
        case 3: return RoutingInstruction::RoundaboutThirdExit; break;
        default: return RoutingInstruction::RoundaboutExit;
        }
    } else if ( instruction == "12" ) {
        return RoutingInstruction::RoundaboutExit;
    }

    // ignoring ReachViaPoint = 9;
    // ignoring StayOnRoundAbout = 13;
    // ignoring StartAtEndOfStreet = 14;
    // ignoring ReachedYourDestination = 15;

    return RoutingInstruction::Unknown;
}

GeoDataDocument *OSRMRunner::parse( const QByteArray &input )
{
    QScriptEngine engine;
    // Qt requires parentheses around json code
    QScriptValue const data = engine.evaluate( '(' + QString::fromUtf8( input ) + ')' );

    GeoDataDocument* result = 0;
    GeoDataLineString* routeWaypoints = 0;
    if ( data.property( "route_geometry" ).isString() ) {
        result = new GeoDataDocument();
        result->setName( "Open Source Routing Machine" );
        GeoDataPlacemark* routePlacemark = new GeoDataPlacemark;
        routePlacemark->setName( "Route" );
        routeWaypoints = decodePolyline( data.property( "route_geometry" ).toString() );
        routePlacemark->setGeometry( routeWaypoints );

        QString name = "%1 %2 (OSRM)";
        QString unit = QLatin1String( "m" );
        qreal length = routeWaypoints->length( EARTH_RADIUS );
        if (length >= 1000) {
            length /= 1000.0;
            unit = "km";
        }
        result->setName( name.arg( length, 0, 'f', 1 ).arg( unit ) );
        result->append( routePlacemark );
    }

    if ( result && routeWaypoints && data.property( "route_instructions" ).isArray() ) {
        bool first = true;
        QScriptValueIterator iterator( data.property( "route_instructions" ) );
        GeoDataPlacemark* instruction = new GeoDataPlacemark;
        int lastWaypointIndex = 0;
        while ( iterator.hasNext() ) {
            iterator.next();
            QVariantList details = iterator.value().toVariant().toList();
            if ( details.size() > 7 ) {
                QString const text = details.at( 0 ).toString();
                QString const road = details.at( 1 ).toString();
                int const waypointIndex = details.at( 3 ).toInt();

                if ( waypointIndex < routeWaypoints->size() ) {
                    if ( iterator.hasNext() ) {
                        GeoDataLineString *lineString = new GeoDataLineString;
                        for ( int i=lastWaypointIndex; i<=waypointIndex; ++i ) {
                            lineString->append(routeWaypoints->at( i ) );
                        }
                        instruction->setGeometry( lineString );
                        result->append( instruction );
                        instruction = new GeoDataPlacemark;
                    }
                    lastWaypointIndex = waypointIndex;
                    GeoDataExtendedData extendedData;
                    GeoDataData turnTypeData;
                    turnTypeData.setName( "turnType" );
                    RoutingInstruction::TurnType turnType = parseTurnType( text );
                    turnTypeData.setValue( turnType );
                    extendedData.addValue( turnTypeData );
                    if (!road.isEmpty()) {
                        GeoDataData roadName;
                        roadName.setName( "roadName" );
                        roadName.setValue( road );
                        extendedData.addValue( roadName );
                    }

                    if ( first ) {
                        turnType = RoutingInstruction::Continue;
                        first = false;
                    }

                    if ( turnType == RoutingInstruction::Unknown ) {
                        instruction->setName( text );
                    } else {
                        instruction->setName( RoutingInstruction::generateRoadInstruction( turnType, road ) );
                    }
                    instruction->setExtendedData( extendedData );

                    if ( !iterator.hasNext() && lastWaypointIndex > 0 ) {
                        GeoDataLineString *lineString = new GeoDataLineString;
                        for ( int i=lastWaypointIndex; i<waypointIndex; ++i ) {
                            lineString->append(routeWaypoints->at( i ) );
                        }
                        instruction->setGeometry( lineString );
                        result->append( instruction );
                    }
                }
            }
        }
    }

    if ( data.property( "hint_data" ).isValid() ) {
        QVariantList hints = data.property( "hint_data" ).property( "locations" ).toVariant().toList();
        if ( hints.size() == m_cachedHints.size() ) {
            for ( int i=0; i<m_cachedHints.size(); ++i ) {
                m_cachedHints[i].second = hints[i].toString();
            }
        }

        m_hintChecksum = data.property( "hint_data" ).property( "checksum" ).toString();
    }

    return result;
}

} // namespace Marble

#include "OSRMRunner.moc"
<|endoftext|>


<commit_before>//===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a printer that converts from our internal representation
// of machine-dependent LLVM code to GAS-format SPARC assembly language.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "asm-printer"
#include "Sparc.h"
#include "SparcInstrInfo.h"
#include "SparcTargetMachine.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Target/TargetRegistry.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/FormattedStream.h"
using namespace llvm;

namespace {
  class SparcAsmPrinter : public AsmPrinter {
  public:
    explicit SparcAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
                             MCContext &Ctx, MCStreamer &Streamer,
                             const MCAsmInfo *T)
      : AsmPrinter(O, TM, Ctx, Streamer, T) {}

    virtual const char *getPassName() const {
      return "Sparc Assembly Printer";
    }

    void printOperand(const MachineInstr *MI, int opNum);
    void printMemOperand(const MachineInstr *MI, int opNum,
                         const char *Modifier = 0);
    void printCCOperand(const MachineInstr *MI, int opNum);

    virtual void EmitInstruction(const MachineInstr *MI) {
      printInstruction(MI);
      OutStreamer.AddBlankLine();
    }
    void printInstruction(const MachineInstr *MI);  // autogenerated.
    static const char *getRegisterName(unsigned RegNo);

    bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
                       unsigned AsmVariant, const char *ExtraCode);
    bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
                             unsigned AsmVariant, const char *ExtraCode);

    bool printGetPCX(const MachineInstr *MI, unsigned OpNo);

    virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB)
                       const;
  };
} // end of anonymous namespace

#include "SparcGenAsmWriter.inc"

void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
  const MachineOperand &MO = MI->getOperand (opNum);
  bool CloseParen = false;
  if (MI->getOpcode() == SP::SETHIi && !MO.isReg() && !MO.isImm()) {
    O << "%hi(";
    CloseParen = true;
  } else if ((MI->getOpcode() == SP::ORri || MI->getOpcode() == SP::ADDri) &&
             !MO.isReg() && !MO.isImm()) {
    O << "%lo(";
    CloseParen = true;
  }
  switch (MO.getType()) {
  case MachineOperand::MO_Register:
    O << "%" << LowercaseString(getRegisterName(MO.getReg()));
    break;

  case MachineOperand::MO_Immediate:
    O << (int)MO.getImm();
    break;
  case MachineOperand::MO_MachineBasicBlock:
    O << *MO.getMBB()->getSymbol(OutContext);
    return;
  case MachineOperand::MO_GlobalAddress:
    O << *GetGlobalValueSymbol(MO.getGlobal());
    break;
  case MachineOperand::MO_ExternalSymbol:
    O << MO.getSymbolName();
    break;
  case MachineOperand::MO_ConstantPoolIndex:
    O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
      << MO.getIndex();
    break;
  default:
    llvm_unreachable("<unknown operand type>");
  }
  if (CloseParen) O << ")";
}

void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
                                      const char *Modifier) {
  printOperand(MI, opNum);

  // If this is an ADD operand, emit it like normal operands.
  if (Modifier && !strcmp(Modifier, "arith")) {
    O << ", ";
    printOperand(MI, opNum+1);
    return;
  }

  if (MI->getOperand(opNum+1).isReg() &&
      MI->getOperand(opNum+1).getReg() == SP::G0)
    return;   // don't print "+%g0"
  if (MI->getOperand(opNum+1).isImm() &&
      MI->getOperand(opNum+1).getImm() == 0)
    return;   // don't print "+0"

  O << "+";
  if (MI->getOperand(opNum+1).isGlobal() ||
      MI->getOperand(opNum+1).isCPI()) {
    O << "%lo(";
    printOperand(MI, opNum+1);
    O << ")";
  } else {
    printOperand(MI, opNum+1);
  }
}

bool SparcAsmPrinter::printGetPCX(const MachineInstr *MI, unsigned opNum) {
  std::string operand = "";
  const MachineOperand &MO = MI->getOperand(opNum);
  switch (MO.getType()) {
  default: assert(0 && "Operand is not a register ");
  case MachineOperand::MO_Register:
    assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
           "Operand is not a physical register ");
    operand = "%" + LowercaseString(getRegisterName(MO.getReg()));
    break;
  }

  unsigned bbNum = MI->getParent()->getNumber();

  O << '\n' << ".LLGETPCH" << bbNum << ":\n";
  O << "\tcall\t.LLGETPC" << bbNum << '\n' ;

  O << "\t  sethi\t"
    << "%hi(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << bbNum << ")), "
    << operand << '\n' ;

  O << ".LLGETPC" << bbNum << ":\n" ;
  O << "\tor\t" << operand
    << ", %lo(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << bbNum << ")), "
    << operand << '\n';
  O << "\tadd\t" << operand << ", %o7, " << operand << '\n';

  return true;
}

void SparcAsmPrinter::printCCOperand(const MachineInstr *MI, int opNum) {
  int CC = (int)MI->getOperand(opNum).getImm();
  O << SPARCCondCodeToString((SPCC::CondCodes)CC);
}

/// PrintAsmOperand - Print out an operand for an inline asm expression.
///
bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
                                      unsigned AsmVariant,
                                      const char *ExtraCode) {
  if (ExtraCode && ExtraCode[0]) {
    if (ExtraCode[1] != 0) return true; // Unknown modifier.

    switch (ExtraCode[0]) {
    default: return true;  // Unknown modifier.
    case 'r':
     break;
    }
  }

  printOperand(MI, OpNo);

  return false;
}

bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
                                            unsigned OpNo,
                                            unsigned AsmVariant,
                                            const char *ExtraCode) {
  if (ExtraCode && ExtraCode[0])
    return true;  // Unknown modifier

  O << '[';
  printMemOperand(MI, OpNo);
  O << ']';

  return false;
}

/// isBlockOnlyReachableByFallthough - Return true if the basic block has
/// exactly one predecessor and the control transfer mechanism between
/// the predecessor and this block is a fall-through.
/// Override AsmPrinter implementation to handle delay slots
bool SparcAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB)
    const {
  // If this is a landing pad, it isn't a fall through.  If it has no preds,
  // then nothing falls through to it.
  if (MBB->isLandingPad() || MBB->pred_empty())
    return false;

  // If there isn't exactly one predecessor, it can't be a fall through.
  MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI;
  ++PI2;
  if (PI2 != MBB->pred_end())
    return false;

  // The predecessor has to be immediately before this block.
  const MachineBasicBlock *Pred = *PI;

  if (!Pred->isLayoutSuccessor(MBB))
    return false;

  // Check if the last terminator is an unconditional branch
  MachineBasicBlock::const_iterator I = Pred->end();
  while( I != Pred->begin() && !(--I)->getDesc().isTerminator() )
      ; /* Noop */
  return I == Pred->end() || !I->getDesc().isBarrier();
}

// Force static initialization.
extern "C" void LLVMInitializeSparcAsmPrinter() {
  RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget);
  RegisterAsmPrinter<SparcAsmPrinter> Y(TheSparcV9Target);
}
<commit_msg><commit_after>//===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a printer that converts from our internal representation
// of machine-dependent LLVM code to GAS-format SPARC assembly language.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "asm-printer"
#include "Sparc.h"
#include "SparcInstrInfo.h"
#include "SparcTargetMachine.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Target/TargetRegistry.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/FormattedStream.h"
using namespace llvm;

namespace {
  class SparcAsmPrinter : public AsmPrinter {
  public:
    explicit SparcAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
                             MCContext &Ctx, MCStreamer &Streamer,
                             const MCAsmInfo *T)
      : AsmPrinter(O, TM, Ctx, Streamer, T) {}

    virtual const char *getPassName() const {
      return "Sparc Assembly Printer";
    }

    void printOperand(const MachineInstr *MI, int opNum);
    void printMemOperand(const MachineInstr *MI, int opNum,
                         const char *Modifier = 0);
    void printCCOperand(const MachineInstr *MI, int opNum);

    virtual void EmitInstruction(const MachineInstr *MI) {
      printInstruction(MI);
      OutStreamer.AddBlankLine();
    }
    void printInstruction(const MachineInstr *MI);  // autogenerated.
    static const char *getRegisterName(unsigned RegNo);

    bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
                       unsigned AsmVariant, const char *ExtraCode);
    bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
                             unsigned AsmVariant, const char *ExtraCode);

    bool printGetPCX(const MachineInstr *MI, unsigned OpNo);

    virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB)
                       const;
  };
} // end of anonymous namespace

#include "SparcGenAsmWriter.inc"

void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
  const MachineOperand &MO = MI->getOperand (opNum);
  bool CloseParen = false;
  if (MI->getOpcode() == SP::SETHIi && !MO.isReg() && !MO.isImm()) {
    O << "%hi(";
    CloseParen = true;
  } else if ((MI->getOpcode() == SP::ORri || MI->getOpcode() == SP::ADDri) &&
             !MO.isReg() && !MO.isImm()) {
    O << "%lo(";
    CloseParen = true;
  }
  switch (MO.getType()) {
  case MachineOperand::MO_Register:
    O << "%" << LowercaseString(getRegisterName(MO.getReg()));
    break;

  case MachineOperand::MO_Immediate:
    O << (int)MO.getImm();
    break;
  case MachineOperand::MO_MachineBasicBlock:
    O << *MO.getMBB()->getSymbol(OutContext);
    return;
  case MachineOperand::MO_GlobalAddress:
    O << *GetGlobalValueSymbol(MO.getGlobal());
    break;
  case MachineOperand::MO_ExternalSymbol:
    O << MO.getSymbolName();
    break;
  case MachineOperand::MO_ConstantPoolIndex:
    O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
      << MO.getIndex();
    break;
  default:
    llvm_unreachable("<unknown operand type>");
  }
  if (CloseParen) O << ")";
}

void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
                                      const char *Modifier) {
  printOperand(MI, opNum);

  // If this is an ADD operand, emit it like normal operands.
  if (Modifier && !strcmp(Modifier, "arith")) {
    O << ", ";
    printOperand(MI, opNum+1);
    return;
  }

  if (MI->getOperand(opNum+1).isReg() &&
      MI->getOperand(opNum+1).getReg() == SP::G0)
    return;   // don't print "+%g0"
  if (MI->getOperand(opNum+1).isImm() &&
      MI->getOperand(opNum+1).getImm() == 0)
    return;   // don't print "+0"

  O << "+";
  if (MI->getOperand(opNum+1).isGlobal() ||
      MI->getOperand(opNum+1).isCPI()) {
    O << "%lo(";
    printOperand(MI, opNum+1);
    O << ")";
  } else {
    printOperand(MI, opNum+1);
  }
}

bool SparcAsmPrinter::printGetPCX(const MachineInstr *MI, unsigned opNum) {
  std::string operand = "";
  const MachineOperand &MO = MI->getOperand(opNum);
  switch (MO.getType()) {
  default: assert(0 && "Operand is not a register ");
  case MachineOperand::MO_Register:
    assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
           "Operand is not a physical register ");
    operand = "%" + LowercaseString(getRegisterName(MO.getReg()));
    break;
  }

  unsigned mfNum = MI->getParent()->getParent()->getFunctionNumber();
  unsigned bbNum = MI->getParent()->getNumber();

  O << '\n' << ".LLGETPCH" << mfNum << '_' << bbNum << ":\n";
  O << "\tcall\t.LLGETPC" << mfNum << '_' << bbNum << '\n' ;

  O << "\t  sethi\t"
    << "%hi(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum << ")), "
    << operand << '\n' ;

  O << ".LLGETPC" << mfNum << '_' << bbNum << ":\n" ;
  O << "\tor\t" << operand
    << ", %lo(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum << ")), "
    << operand << '\n';
  O << "\tadd\t" << operand << ", %o7, " << operand << '\n';

  return true;
}

void SparcAsmPrinter::printCCOperand(const MachineInstr *MI, int opNum) {
  int CC = (int)MI->getOperand(opNum).getImm();
  O << SPARCCondCodeToString((SPCC::CondCodes)CC);
}

/// PrintAsmOperand - Print out an operand for an inline asm expression.
///
bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
                                      unsigned AsmVariant,
                                      const char *ExtraCode) {
  if (ExtraCode && ExtraCode[0]) {
    if (ExtraCode[1] != 0) return true; // Unknown modifier.

    switch (ExtraCode[0]) {
    default: return true;  // Unknown modifier.
    case 'r':
     break;
    }
  }

  printOperand(MI, OpNo);

  return false;
}

bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
                                            unsigned OpNo,
                                            unsigned AsmVariant,
                                            const char *ExtraCode) {
  if (ExtraCode && ExtraCode[0])
    return true;  // Unknown modifier

  O << '[';
  printMemOperand(MI, OpNo);
  O << ']';

  return false;
}

/// isBlockOnlyReachableByFallthough - Return true if the basic block has
/// exactly one predecessor and the control transfer mechanism between
/// the predecessor and this block is a fall-through.
/// Override AsmPrinter implementation to handle delay slots
bool SparcAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB)
    const {
  // If this is a landing pad, it isn't a fall through.  If it has no preds,
  // then nothing falls through to it.
  if (MBB->isLandingPad() || MBB->pred_empty())
    return false;

  // If there isn't exactly one predecessor, it can't be a fall through.
  MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI;
  ++PI2;
  if (PI2 != MBB->pred_end())
    return false;

  // The predecessor has to be immediately before this block.
  const MachineBasicBlock *Pred = *PI;

  if (!Pred->isLayoutSuccessor(MBB))
    return false;

  // Check if the last terminator is an unconditional branch
  MachineBasicBlock::const_iterator I = Pred->end();
  while( I != Pred->begin() && !(--I)->getDesc().isTerminator() )
      ; /* Noop */
  return I == Pred->end() || !I->getDesc().isBarrier();
}

// Force static initialization.
extern "C" void LLVMInitializeSparcAsmPrinter() {
  RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget);
  RegisterAsmPrinter<SparcAsmPrinter> Y(TheSparcV9Target);
}
<|endoftext|>


<commit_before>#include <stan/agrad/rev/operators/operator_not_equal.hpp>
#include <test/unit/agrad/util.hpp>
#include <gtest/gtest.h>

TEST(AgradRev,a_neq_y) {
  AVAR a = 2.0;
  double y = 3.0;
  EXPECT_TRUE(a != y);
  EXPECT_TRUE(y != a);
  double z = 2.0;
  EXPECT_FALSE(a != z);
  EXPECT_FALSE(z != a);
}
<commit_msg>add NaN test for operator_not_equal<commit_after>#include <stan/agrad/rev/operators/operator_not_equal.hpp>
#include <test/unit/agrad/util.hpp>
#include <gtest/gtest.h>

TEST(AgradRev,a_neq_y) {
  AVAR a = 2.0;
  double y = 3.0;
  EXPECT_TRUE(a != y);
  EXPECT_TRUE(y != a);
  double z = 2.0;
  EXPECT_FALSE(a != z);
  EXPECT_FALSE(z != a);
}

TEST(AgradRev, logical_neq_nan) {
  stan::agrad::var nan = std::numeric_limits<double>::quiet_NaN();
  stan::agrad::var a = 1.0;
  stan::agrad::var b = 2.0;
  double nan_dbl = std::numeric_limits<double>::quiet_NaN();

  EXPECT_TRUE(1.0 != nan);
  EXPECT_TRUE(nan != 2.0);
  EXPECT_TRUE(nan != nan);
  EXPECT_TRUE(a != nan);
  EXPECT_TRUE(nan != b);
  EXPECT_TRUE(a != nan_dbl);
  EXPECT_TRUE(nan_dbl != b);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: dp_gui_dialog2.hxx,v $
 *
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef INCLUDED_DP_GUI_DIALOG2_HXX
#define INCLUDED_DP_GUI_DIALOG2_HXX

#include "vcl/dialog.hxx"
#include "vcl/button.hxx"
#include "vcl/fixed.hxx"
#include "vcl/timer.hxx"

#include "svtools/fixedhyper.hxx"
#include "svtools/prgsbar.hxx"

#include "osl/conditn.hxx"
#include "osl/mutex.hxx"

#include "rtl/ref.hxx"
#include "rtl/ustring.hxx"

#include "com/sun/star/deployment/XPackage.hpp"
#include "com/sun/star/deployment/XPackageManager.hpp"
#include "com/sun/star/util/XModifyListener.hpp"

namespace dp_gui {

//==============================================================================
class ExtensionBox_Impl;
class TheExtensionManager;

//==============================================================================
class ExtMgrDialog : public ModelessDialog
{
    ExtensionBox_Impl   *m_pExtensionBox;
    PushButton           m_aAddBtn;
    PushButton           m_aUpdateBtn;
    OKButton             m_aCloseBtn;
    HelpButton           m_aHelpBtn;
    FixedLine            m_aDivider;
    svt::FixedHyperlink  m_aGetExtensions;
    FixedText            m_aProgressText;
    ProgressBar          m_aProgressBar;
    CancelButton         m_aCancelBtn;
    const String         m_sAddPackages;
    String               m_sProgressText;
    ::osl::Mutex         m_aMutex;
    bool                 m_bHasProgress;
    bool                 m_bProgressChanged;
    bool                 m_bStartProgress;
    bool                 m_bStopProgress;
    bool                 m_bUpdateWarning;
    bool                 m_bEnableWarning;
    bool                 m_bDisableWarning;
    bool                 m_bDeleteWarning;
    bool                 m_bHasSharedExtensions;
    long                 m_nProgress;
    Timer                m_aTimeoutTimer;
    TheExtensionManager *m_pManager;

    ::com::sun::star::uno::Reference< ::com::sun::star::task::XAbortChannel > m_xAbortChannel;

    bool continueOnSharedExtension( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &,
                                    const USHORT nResID,
                                    bool &bHadWarning ) const;

    DECL_DLLPRIVATE_LINK( HandleAddBtn, void * );
    DECL_DLLPRIVATE_LINK( HandleUpdateBtn, void * );
    DECL_DLLPRIVATE_LINK( HandleCancelBtn, void * );
    DECL_DLLPRIVATE_LINK( HandleGetExtensions, svt::FixedHyperlink * );
    DECL_DLLPRIVATE_LINK( TimeOutHdl, Timer* );
    DECL_DLLPRIVATE_LINK( startProgress, ::osl::Condition * );

public:
                    ExtMgrDialog( Window * pParent, TheExtensionManager *pManager );
    virtual        ~ExtMgrDialog();

    virtual void    Resize();
    virtual long    Notify( NotifyEvent& rNEvt );
    virtual BOOL    Close();

    void            setGetExtensionsURL( const ::rtl::OUString &rURL );
    void            selectEntry( long nPos );
    long            addPackageToList( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &,
                                      const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > & );
    bool enablePackage( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &xPackageManager,
                        const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage,
                        bool bEnable );
    bool removePackage( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &xPackageManager,
                        const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage );
    bool updatePackage( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &xPackageManager,
                        const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage );

    void            showProgress( bool bStart );
    void            updateProgress( const ::rtl::OUString &rText,
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::task::XAbortChannel > &xAbortChannel);
    void            updateProgress( const long nProgress );
    void            updatePackageInfo( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage );
    void            removeEntry( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage );

    void            prepareChecking( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &xPackageManager );
    void            checkEntries();

    ::com::sun::star::uno::Sequence< ::rtl::OUString > raiseAddPicker( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &xPackageManager );

    void            openWebBrowser( ::rtl::OUString const &sURL ) const;

    bool            installForAllUsers( bool &bInstallForAll ) const;
    bool            installExtensionWarn( const ::rtl::OUString &rExtensionURL ) const;

    static ResId    getResId( USHORT id );
    static String   getResourceString( USHORT id );
    static bool     IsSharedPkgMgr( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &);
};

} // namespace dp_gui

#endif
<commit_msg>INTEGRATION: CWS extmgrui03 (1.3.6); FILE MERGED 2008/05/28 12:13:40 dv 1.3.6.1: #i90052# Add publisher link to new Extension Manager UI<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: dp_gui_dialog2.hxx,v $
 *
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef INCLUDED_DP_GUI_DIALOG2_HXX
#define INCLUDED_DP_GUI_DIALOG2_HXX

#include "vcl/dialog.hxx"
#include "vcl/button.hxx"
#include "vcl/fixed.hxx"
#include "vcl/timer.hxx"

#include "svtools/fixedhyper.hxx"
#include "svtools/prgsbar.hxx"

#include "osl/conditn.hxx"
#include "osl/mutex.hxx"

#include "rtl/ref.hxx"
#include "rtl/ustring.hxx"

#include "com/sun/star/deployment/XPackage.hpp"
#include "com/sun/star/deployment/XPackageManager.hpp"
#include "com/sun/star/util/XModifyListener.hpp"

namespace dp_gui {

//==============================================================================
class ExtensionBox_Impl;
class TheExtensionManager;

//==============================================================================
class ExtMgrDialog : public ModelessDialog
{
    ExtensionBox_Impl   *m_pExtensionBox;
    PushButton           m_aAddBtn;
    PushButton           m_aUpdateBtn;
    OKButton             m_aCloseBtn;
    HelpButton           m_aHelpBtn;
    FixedLine            m_aDivider;
    svt::FixedHyperlink  m_aGetExtensions;
    FixedText            m_aProgressText;
    ProgressBar          m_aProgressBar;
    CancelButton         m_aCancelBtn;
    const String         m_sAddPackages;
    String               m_sProgressText;
    ::osl::Mutex         m_aMutex;
    bool                 m_bHasProgress;
    bool                 m_bProgressChanged;
    bool                 m_bStartProgress;
    bool                 m_bStopProgress;
    bool                 m_bUpdateWarning;
    bool                 m_bEnableWarning;
    bool                 m_bDisableWarning;
    bool                 m_bDeleteWarning;
    bool                 m_bHasSharedExtensions;
    long                 m_nProgress;
    Timer                m_aTimeoutTimer;
    TheExtensionManager *m_pManager;

    ::com::sun::star::uno::Reference< ::com::sun::star::task::XAbortChannel > m_xAbortChannel;

    bool continueOnSharedExtension( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &,
                                    const USHORT nResID,
                                    bool &bHadWarning ) const;

    DECL_DLLPRIVATE_LINK( HandleAddBtn, void * );
    DECL_DLLPRIVATE_LINK( HandleUpdateBtn, void * );
    DECL_DLLPRIVATE_LINK( HandleCancelBtn, void * );
    DECL_DLLPRIVATE_LINK( HandleHyperlink, svt::FixedHyperlink * );
    DECL_DLLPRIVATE_LINK( TimeOutHdl, Timer* );
    DECL_DLLPRIVATE_LINK( startProgress, ::osl::Condition * );

public:
                    ExtMgrDialog( Window * pParent, TheExtensionManager *pManager );
    virtual        ~ExtMgrDialog();

    virtual void    Resize();
    virtual long    Notify( NotifyEvent& rNEvt );
    virtual BOOL    Close();

    void            setGetExtensionsURL( const ::rtl::OUString &rURL );
    void            selectEntry( long nPos );
    long            addPackageToList( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &,
                                      const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > & );
    bool enablePackage( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &xPackageManager,
                        const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage,
                        bool bEnable );
    bool removePackage( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &xPackageManager,
                        const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage );
    bool updatePackage( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &xPackageManager,
                        const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage );

    void            showProgress( bool bStart );
    void            updateProgress( const ::rtl::OUString &rText,
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::task::XAbortChannel > &xAbortChannel);
    void            updateProgress( const long nProgress );
    void            updatePackageInfo( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage );
    void            removeEntry( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage );

    void            prepareChecking( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &xPackageManager );
    void            checkEntries();

    ::com::sun::star::uno::Sequence< ::rtl::OUString > raiseAddPicker( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &xPackageManager );

    void            openWebBrowser( ::rtl::OUString const &sURL ) const;

    bool            installForAllUsers( bool &bInstallForAll ) const;
    bool            installExtensionWarn( const ::rtl::OUString &rExtensionURL ) const;

    static ResId    getResId( USHORT id );
    static String   getResourceString( USHORT id );
    static bool     IsSharedPkgMgr( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &);
};

} // namespace dp_gui

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008 Pelle Johansson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
 */

#include "backend.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <event.h>
#include <err.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <search.h>
#include <stdio.h>
#include <sys/queue.h>
#include <fcntl.h>
#include <stdarg.h>
#include <netinet/in.h>
#include <sys/stat.h>

#include <forward_list>
#include <functional>
#include <list>
#include <string>

#include "status.h"
#include "line.h"
#include "api_serverside.h"
#include "smart_fd.hh"
#include "smart_event.hh"
#include "smart_evbuffer.hh"

#include "backend_type.h"

class output_list
{
	std::forward_list<backend_output> list;
	decltype(list)::iterator send_iter = list.end();
	decltype(list)::iterator insert_iter = list.before_begin();

public:
	decltype(send_iter) to_send()
	{
		if (send_iter == list.end())
			return send_iter;
		return send_iter++;
	}

	const backend_output *inptr()
	{
		if (list.empty() || send_iter == list.begin())
			return NULL;
		return &list.front();
	}

	void push(backend_output o)
	{
		insert_iter = list.insert_after(insert_iter, std::move(o));
		if (send_iter == list.end())
			send_iter = insert_iter;
	}

	void pop()
	{
		if (insert_iter == list.begin())
			insert_iter = list.before_begin();
		list.pop_front();
	}

	void clear()
	{
		list.clear();
		send_iter = list.end();
		insert_iter = list.before_begin();
	}

	decltype(list.end()) end()
	{
		return list.end();
	}
};

struct backend_device {
	std::string name;

	std::string line;
	smart_fd line_fd;
	smart_event read_ev;
	smart_event write_ev;

	smart_evbuffer input;
	output_list output;
	struct timeval out_throttle;

	std::string client;

	struct status status;

	backend_device(std::string name, const struct status_dispatch *dispatch, std::string line, std::string client, int throttle);

	void open();
	void close();

private:
	void readcb(short what);
	void writecb();
};

std::list<backend_device> backends;

void
add_backend_device(const char *str) {
	int ms = 0;
	const char *next;

	next = strchr(str, ':');

	if (!next)
		errx (1, "No type for backend: %s", str);

	std::string name(str, next - str);

	str = next + 1;
	next = strchr(str, ':');
	if (!next)
		errx (1, "No path for backend: %s:%s", name.c_str(), str);

	std::string type(str, next - str);
	str = next + 1;
	next = strchr(str, ':');

	std::string path, client;
	if (next) {
		path = std::string(str, next - str);

		str = next + 1;
		next = strchr(str, ':');
		if (next) {
			client = std::string(str, next - str);
			ms = atoi(next + 1);
		} else {
			client = std::string(str);
		}
	} else {
		path = std::string(str);
	}

	const struct backend_type *bt = backend_type(type.c_str(), type.length());
	if (!bt)
		errx (1, "Unknown device type: %s", type.c_str());

	backends.emplace_back(name, bt->dispatch, path, client, ms);
}

backend_device::backend_device(std::string name, const struct status_dispatch *dispatch, std::string line,
		std::string client, int throttle)
	: name(std::move(name)), line(std::move(line)), client(std::move(client))
{
	status.dispatch = dispatch;
	out_throttle.tv_sec = throttle / 1000;
	out_throttle.tv_usec = (throttle % 1000) * 1000;
}

void
backend_device::readcb(short what) {
	size_t len;

	int res = input.read(line_fd, 1024);
	if (res < 0)
		err (1, "evbuffer_read");
	if (res == 0)
		event_loopexit (NULL);

	while ((len = input.length())) {
		unsigned char *data = input.data();
		size_t i;

		for (i = 0 ; i < len ; i++) {
			if (strchr(status.dispatch->packet_separators, data[i]))
				break;
		}
		if (i == len)
			break;

		if (i > 0) {
			data[i] = '\0';
			status.dispatch->update_status(this, &status, (char*)data, output.inptr());
		}
		input.drain(i + 1);
	}
}

void
backend_device::writecb() {
	auto out = output.to_send();

	if (out == output.end())
		return;

	if (write (line_fd, out->data, out->len) != out->len)
		err (1, "write");

	if (out->throttle.tv_sec > 0 || out->throttle.tv_usec > 0)
		write_ev.add(out->throttle);
	else
		write_ev.add(out_throttle);
}

void
backend_device::open()
{
	line_fd = open_line (line.c_str(), O_RDWR);
	if (!line_fd)
		err (1, "open_line");

	read_ev.set_fd(line_fd);
	read_ev.set(EV_READ | EV_PERSIST, std::bind(&backend_device::readcb, this, std::placeholders::_2));
	write_ev.set(EV_TIMEOUT, std::bind(&backend_device::writecb, this));

	if (read_ev.add())
		err (1, "event_add");
}

void
backend_device::close()
{
	read_ev.reset();
	write_ev.reset();
	input.reset();
	line_fd.close();

	output.clear();
}

void
backend_reopen_devices(void)
{
	for (auto &bdev : backends) {
		bdev.close();
		bdev.open();

		bdev.status.dispatch->status_setup(&bdev, &bdev.status);
	}
}

void
backend_listen_fd (const char *name, int fd) {
	decltype(backends)::iterator bdev;
	struct sockaddr_storage sst;
	socklen_t sstlen;
	char tag[32];

	for (bdev = backends.begin() ; bdev != backends.end() ; bdev++) {
		if (name == bdev->name)
			break;
	}
	if (bdev == backends.end())
		errx (1, "backend_listen: No matching device %s", name);

	strlcpy(tag, bdev->name.c_str(), sizeof(tag));

	sstlen = sizeof (sst);
	if (getsockname(fd, (struct sockaddr*)&sst, &sstlen) == 0) {
		if (sst.ss_family == AF_INET || sst.ss_family == AF_INET6) {
			char pbuf[NI_MAXSERV];

			getnameinfo((struct sockaddr*)&sst, sstlen, NULL, 0, pbuf, sizeof(pbuf), NI_NUMERICSERV);
			strlcat(tag, ":", sizeof(tag));
			strlcat(tag, pbuf, sizeof(tag));
		} else if (sst.ss_family == AF_UNIX) {
			struct sockaddr_un *sun = (struct sockaddr_un*)&sst;
			char path[256];

			if (sscanf(sun->sun_path, "/var/run/movactl.%s", path) == 1) {
				char *cp = strchr(path, '.');
				if (cp)
					*cp = '\0';
				strlcpy(tag, path, sizeof(tag));
			} else
				warnx("sscanf failed: %s", sun->sun_path);
		}
	}

	serverside_listen_fd(tag, &*bdev, fd);
}

void
backend_listen_all (void)
{
	for (auto bdev = backends.begin() ; bdev != backends.end() ; bdev++) {
		char *e = NULL;
		int p;
		char *c, *client, *cl;

		if (bdev->client.empty())
			continue;

		cl = client = strdup(bdev->client.c_str());
		if (!client)
			err(1, "backend_listen_all");

		while ((c = strsep(&client, ","))) {
			if ((p = strtol(c, &e, 0)) > 0 && p < 65536 && e && *e == '\0') {
				char tag[32];

				snprintf(tag, sizeof(tag), "%s:%s", bdev->name.c_str(), c);
				serverside_listen_tcp(tag, &*bdev, c);
			} else {
				char path[256];
				char tag[32];

				if (sscanf(c, "/var/run/movactl.%s.sock", path) == 1) {
					char *cp = strchr(path, '.');

					if (cp)
						*cp = '\0';
					strlcpy(tag, path, sizeof(tag));
				} else
					strlcpy(tag, bdev->name.c_str(), sizeof(tag));
				serverside_listen_local(tag, &*bdev, c);
			}
		}
		free(cl);
	}
}

void
backend_close_all (void)
{
	for (auto bdev = backends.begin() ; bdev != backends.end() ; bdev++) {
		bdev->close();
	}
}

static void
backend_send_impl(struct backend_device *bdev, const struct timeval *throttle, const char *fmt, va_list ap) {
	backend_output out;

	out.len = vasprintf(&out.data, fmt, ap);
	if (out.len < 0)
		err (1, "vasprintf");

	if (throttle)
		out.throttle = *throttle;
	else
		memset(&out.throttle, 0, sizeof (out.throttle));

	bdev->output.push(out);
}

void
backend_send(struct backend_device *bdev, const char *fmt, ...) {
	va_list ap;

	va_start(ap, fmt);
	backend_send_impl(bdev, NULL, fmt, ap);
	va_end(ap);
}

void
backend_send_throttle(struct backend_device *bdev, const struct timeval *throttle, const char *fmt, ...) {
	va_list ap;

	va_start(ap, fmt);
	backend_send_impl(bdev, throttle, fmt, ap);
	va_end(ap);
}

void
backend_remove_output(struct backend_device *bdev, const struct backend_output **inptr) {
	const struct backend_output *out = *inptr;

	if (out != bdev->output.inptr()) {
		if (out)
			throw 1;
		return;
	}

	free(out->data);
	bdev->output.pop();
	*inptr = bdev->output.inptr();
}

void
backend_send_command(struct backend_device *bdev, const char *cmd, int narg, int32_t *args) {
	bdev->status.dispatch->send_command(bdev, cmd, narg, args);
}

struct status *
backend_get_status(struct backend_device *bdev) {
	return &bdev->status;
}

void
backend_send_status_request(struct backend_device *bdev, const char *code) {
	 bdev->status.dispatch->send_status_request(bdev, code);
}
<commit_msg>Convert functions to methods where appropriate.<commit_after>/*
 * Copyright (c) 2008 Pelle Johansson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
 */

#include "backend.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <event.h>
#include <err.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <search.h>
#include <stdio.h>
#include <sys/queue.h>
#include <fcntl.h>
#include <stdarg.h>
#include <netinet/in.h>
#include <sys/stat.h>

#include <forward_list>
#include <functional>
#include <list>
#include <sstream>
#include <string>

#include "status.h"
#include "line.h"
#include "api_serverside.h"
#include "smart_fd.hh"
#include "smart_event.hh"
#include "smart_evbuffer.hh"

#include "backend_type.h"

class output_list
{
	std::forward_list<backend_output> list;
	decltype(list)::iterator send_iter = list.end();
	decltype(list)::iterator insert_iter = list.before_begin();

public:
	decltype(send_iter) to_send()
	{
		if (send_iter == list.end())
			return send_iter;
		return send_iter++;
	}

	const backend_output *inptr()
	{
		if (list.empty() || send_iter == list.begin())
			return NULL;
		return &list.front();
	}

	void push(backend_output o)
	{
		insert_iter = list.insert_after(insert_iter, std::move(o));
		if (send_iter == list.end())
			send_iter = insert_iter;
	}

	void pop()
	{
		if (insert_iter == list.begin())
			insert_iter = list.before_begin();
		list.pop_front();
	}

	void clear()
	{
		list.clear();
		send_iter = list.end();
		insert_iter = list.before_begin();
	}

	decltype(list.end()) end()
	{
		return list.end();
	}
};

struct backend_device {
	std::string name;

	std::string line;
	smart_fd line_fd;
	smart_event read_ev;
	smart_event write_ev;

	smart_evbuffer input;
	output_list output;
	struct timeval out_throttle;

	std::string client;

	struct status status;

	backend_device(std::string name, const struct status_dispatch *dispatch, std::string line, std::string client, int throttle);

	void open();
	void close();

	void listen(int fd);
	void listen_to_client();

	void send(const struct timeval *throttle, const char *fmt, va_list ap);
	void remove_output(const struct backend_output **inptr);

private:
	void readcb(short what);
	void writecb();
};

std::list<backend_device> backends;

void
add_backend_device(const char *str) {
	int ms = 0;
	const char *next;

	next = strchr(str, ':');

	if (!next)
		errx (1, "No type for backend: %s", str);

	std::string name(str, next - str);

	str = next + 1;
	next = strchr(str, ':');
	if (!next)
		errx (1, "No path for backend: %s:%s", name.c_str(), str);

	std::string type(str, next - str);
	str = next + 1;
	next = strchr(str, ':');

	std::string path, client;
	if (next) {
		path = std::string(str, next - str);

		str = next + 1;
		next = strchr(str, ':');
		if (next) {
			client = std::string(str, next - str);
			ms = atoi(next + 1);
		} else {
			client = std::string(str);
		}
	} else {
		path = std::string(str);
	}

	const struct backend_type *bt = backend_type(type.c_str(), type.length());
	if (!bt)
		errx (1, "Unknown device type: %s", type.c_str());

	backends.emplace_back(name, bt->dispatch, path, client, ms);
}

backend_device::backend_device(std::string name, const struct status_dispatch *dispatch, std::string line,
		std::string client, int throttle)
	: name(std::move(name)), line(std::move(line)), client(std::move(client))
{
	status.dispatch = dispatch;
	out_throttle.tv_sec = throttle / 1000;
	out_throttle.tv_usec = (throttle % 1000) * 1000;
}

void
backend_device::readcb(short what) {
	size_t len;

	int res = input.read(line_fd, 1024);
	if (res < 0)
		err (1, "evbuffer_read");
	if (res == 0)
		event_loopexit (NULL);

	while ((len = input.length())) {
		unsigned char *data = input.data();
		size_t i;

		for (i = 0 ; i < len ; i++) {
			if (strchr(status.dispatch->packet_separators, data[i]))
				break;
		}
		if (i == len)
			break;

		if (i > 0) {
			data[i] = '\0';
			status.dispatch->update_status(this, &status, (char*)data, output.inptr());
		}
		input.drain(i + 1);
	}
}

void
backend_device::writecb() {
	auto out = output.to_send();

	if (out == output.end())
		return;

	if (write (line_fd, out->data, out->len) != out->len)
		err (1, "write");

	if (out->throttle.tv_sec > 0 || out->throttle.tv_usec > 0)
		write_ev.add(out->throttle);
	else
		write_ev.add(out_throttle);
}

void
backend_device::open()
{
	line_fd = open_line (line.c_str(), O_RDWR);
	if (!line_fd)
		err (1, "open_line");

	read_ev.set_fd(line_fd);
	read_ev.set(EV_READ | EV_PERSIST, std::bind(&backend_device::readcb, this, std::placeholders::_2));
	write_ev.set(EV_TIMEOUT, std::bind(&backend_device::writecb, this));

	if (read_ev.add())
		err (1, "event_add");
}

void
backend_device::close()
{
	read_ev.reset();
	write_ev.reset();
	input.reset();
	line_fd.close();

	output.clear();
}

void
backend_reopen_devices(void)
{
	for (auto &bdev : backends) {
		bdev.close();
		bdev.open();

		bdev.status.dispatch->status_setup(&bdev, &bdev.status);
	}
}

void
backend_device::listen(int fd)
{
	struct sockaddr_storage sst;
	socklen_t sstlen;
	std::string tag = name;

	sstlen = sizeof (sst);
	if (getsockname(fd, (struct sockaddr*)&sst, &sstlen) == 0) {
		if (sst.ss_family == AF_INET || sst.ss_family == AF_INET6) {
			char pbuf[NI_MAXSERV];

			getnameinfo((struct sockaddr*)&sst, sstlen, NULL, 0, pbuf, sizeof(pbuf), NI_NUMERICSERV);
			tag += ":";
			tag += pbuf;
		} else if (sst.ss_family == AF_UNIX) {
			struct sockaddr_un *sun = (struct sockaddr_un*)&sst;
			char path[256];

			if (sscanf(sun->sun_path, "/var/run/movactl.%s", path) == 1) {
				char *cp = strchr(path, '.');
				if (cp)
					*cp = '\0';
				tag = path;
			} else
				warnx("sscanf failed: %s", sun->sun_path);
		}
	}

	serverside_listen_fd(tag.c_str(), this, fd);
}

void
backend_listen_fd(const char *name, int fd)
{
	for (auto &bdev : backends) {
		if (name == bdev.name) {
			bdev.listen(fd);
			return;
		}
	}
	errx (1, "backend_listen: No matching device %s", name);
}

void
backend_device::listen_to_client()
{
	std::istringstream cst{client};
	std::string c;

	while (std::getline(cst, c, ',')) {
		size_t e;
		int p;

		if ((p = std::stoi(c, &e)) > 0 && p < 65536 && e == std::string::npos) {
			std::string tag = name + ":" + c;
			serverside_listen_tcp(tag.c_str(), this, c.c_str());
		} else {
			char path[256];
			std::string tag;

			if (sscanf(c.c_str(), "/var/run/movactl.%s.sock", path) == 1) {
				char *cp = strchr(path, '.');

				if (cp)
					*cp = '\0';
				tag = path;
			} else
				tag = name;
			serverside_listen_local(tag.c_str(), this, c.c_str());
		}
	}
}

void
backend_listen_all(void)
{
	for (auto &bdev : backends) {
		bdev.listen_to_client();
	}
}

void
backend_close_all(void)
{
	for (auto &bdev : backends) {
		bdev.close();
	}
}

void
backend_device::send(const struct timeval *throttle, const char *fmt, va_list ap)
{
	backend_output out;

	out.len = vasprintf(&out.data, fmt, ap);
	if (out.len < 0)
		err (1, "vasprintf");

	if (throttle)
		out.throttle = *throttle;
	else
		memset(&out.throttle, 0, sizeof (out.throttle));

	output.push(out);
}

void
backend_send(struct backend_device *bdev, const char *fmt, ...) {
	va_list ap;

	va_start(ap, fmt);
	bdev->send(NULL, fmt, ap);
	va_end(ap);
}

void
backend_send_throttle(struct backend_device *bdev, const struct timeval *throttle, const char *fmt, ...) {
	va_list ap;

	va_start(ap, fmt);
	bdev->send(throttle, fmt, ap);
	va_end(ap);
}

void
backend_device::remove_output(const struct backend_output **inptr)
{
	const struct backend_output *out = *inptr;

	if (out != output.inptr()) {
		if (out)
			throw 1;
		return;
	}

	free(out->data);
	output.pop();
	*inptr = output.inptr();
}

void
backend_remove_output(struct backend_device *bdev, const struct backend_output **inptr) {
	bdev->remove_output(inptr);
}

void
backend_send_command(struct backend_device *bdev, const char *cmd, int narg, int32_t *args) {
	bdev->status.dispatch->send_command(bdev, cmd, narg, args);
}

struct status *
backend_get_status(struct backend_device *bdev) {
	return &bdev->status;
}

void
backend_send_status_request(struct backend_device *bdev, const char *code) {
	 bdev->status.dispatch->send_status_request(bdev, code);
}
<|endoftext|>


<commit_before><commit_msg>Added coments to easier distinguish which  quarter is which<commit_after><|endoftext|>


<commit_before>/**
 * @file    Manager_test.cpp
 * @ingroup ecs_test
 * @brief   Test of the Entity-Component-System manager.
 *
 * Copyright (c) 2014 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */

#include <ecs/Manager.h>

#include <gtest/gtest.h>

// A test Component
class ComponentTest1 : public ecs::Component {
public:
    static const ecs::ComponentType _mType = 1;
};
class ComponentTest1b : public ecs::Component {
public:
    static const ecs::ComponentType _mType = 1;
};
class ComponentTest2 : public ecs::Component {
public:
    static const ecs::ComponentType _mType = 2;
};

// Creating entities
TEST(Manager, createEntity) {
    ecs::Manager manager;
    EXPECT_EQ(1, manager.createEntity());
    EXPECT_EQ(2, manager.createEntity());
    EXPECT_EQ(3, manager.createEntity());
}

// Creating Component stores
TEST(Manager, createComponentStore) {
    ecs::Manager manager;
    EXPECT_TRUE(manager.createComponentStore<ComponentTest1>());
    EXPECT_FALSE(manager.createComponentStore<ComponentTest1>());
    EXPECT_FALSE(manager.createComponentStore<ComponentTest1b>());
    EXPECT_TRUE(manager.createComponentStore<ComponentTest2>());
    EXPECT_FALSE(manager.createComponentStore<ComponentTest2>());
}<commit_msg>Fixed Google Test compilation warnings<commit_after>/**
 * @file    Manager_test.cpp
 * @ingroup ecs_test
 * @brief   Test of the Entity-Component-System manager.
 *
 * Copyright (c) 2014 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */

#include <ecs/Manager.h>

#include <gtest/gtest.h>

// Test Components
class ComponentTest1 : public ecs::Component {
public:
    static const ecs::ComponentType _mType = 1;
};
class ComponentTest1b : public ecs::Component {
public:
    static const ecs::ComponentType _mType = 1;
};
class ComponentTest2 : public ecs::Component {
public:
    static const ecs::ComponentType _mType = 2;
};

// Creating entities
TEST(Manager, createEntity) {
    ecs::Manager manager;
    EXPECT_EQ((ecs::Entity)1, manager.createEntity());
    EXPECT_EQ((ecs::Entity)2, manager.createEntity());
    EXPECT_EQ((ecs::Entity)3, manager.createEntity());
}

// Creating Component stores
TEST(Manager, createComponentStore) {
    ecs::Manager manager;
    EXPECT_TRUE(manager.createComponentStore<ComponentTest1>());
    EXPECT_FALSE(manager.createComponentStore<ComponentTest1>());
    EXPECT_FALSE(manager.createComponentStore<ComponentTest1b>());
    EXPECT_TRUE(manager.createComponentStore<ComponentTest2>());
    EXPECT_FALSE(manager.createComponentStore<ComponentTest2>());
}<|endoftext|>