<commit_before>/** @file
    @brief Implementation

    @date 2015

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2015 Sensics, 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.

// Internal Includes
#include "EyeTrackerRemoteFactory.h"
#include "VRPNConnectionCollection.h"
#include <osvr/Common/ClientInterface.h>
#include <osvr/Common/PathTreeFull.h>
#include <osvr/Util/ChannelCountC.h>
#include <osvr/Util/UniquePtr.h>
#include <osvr/Common/OriginalSource.h>
#include "InterfaceTree.h"
#include <osvr/Util/Verbosity.h>
#include <osvr/Common/CreateDevice.h>

#include <osvr/Common/EyeTrackerComponent.h>
#include <osvr/Common/Location2DComponent.h>
#include <osvr/Common/DirectionComponent.h>
#include <osvr/Common/RoutingConstants.h>
#include <osvr/Common/InterfaceState.h>

// Library/third-party includes
#include <boost/lexical_cast.hpp>
#include <boost/any.hpp>
#include <boost/variant/get.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>
#include <json/value.h>
#include <json/reader.h>

// Standard includes
#include <iostream>
#include <string>

namespace osvr {
namespace client {

    class NetworkEyeTrackerRemoteHandler : public RemoteHandler {
      public:
        struct Options {
            Options()
                : reportDirection(false), reportBasePoint(false),
                  reportLocation2D(false), reportBlink(false), dirIface() {}
            bool reportDirection;
            bool reportBasePoint;
            bool reportLocation2D;
            bool reportBlink;
            osvr::common::ClientInterfacePtr dirIface;
            osvr::common::ClientInterfacePtr locationIface;
            osvr::common::ClientInterfacePtr trackerIface;
            osvr::common::ClientInterfacePtr buttonIface;
        };

        NetworkEyeTrackerRemoteHandler(
            vrpn_ConnectionPtr const &conn, std::string const &deviceName,
            Options const &options, boost::optional<OSVR_ChannelCount> sensor,
            common::InterfaceList &ifaces)
            : m_dev(common::createClientDevice(deviceName, conn)),
              m_interfaces(ifaces), m_all(!sensor.is_initialized()),
              m_opts(options), m_sensor(sensor) {
            auto eyetracker = common::EyeTrackerComponent::create();
            m_dev->addComponent(eyetracker);
            eyetracker->registerEyeHandler(
                [&](common::OSVR_EyeNotification const &data,
                    util::time::TimeValue const &timestamp) {
                    m_handleEyeTracking(data, timestamp);
                });
            OSVR_DEV_VERBOSE("Constructed an Eye Handler for " << deviceName);
        }

        /// @brief Deleted assignment operator.
        NetworkEyeTrackerRemoteHandler &
        operator=(NetworkEyeTrackerRemoteHandler const &) = delete;

        virtual ~NetworkEyeTrackerRemoteHandler() {
            /// @todo do we need to unregister?
        }

        virtual void update() { m_dev->update(); }

      private:
        void m_handleEyeTracking3d(common::OSVR_EyeNotification const &data,
                                   util::time::TimeValue const &timestamp) {

            OSVR_EyeTracker3DReport report;
            report.sensor = data.sensor;
            report.state.directionValid = false;
            report.state.basePointValid = false;
            util::time::TimeValue timest = timestamp;
            if (m_opts.reportDirection) {
                report.state.directionValid =
                    m_opts.dirIface->getState<OSVR_DirectionReport>(
                        timest, report.state.direction);
            }
            if (m_opts.reportBasePoint) {
                report.state.basePointValid =
                    m_opts.trackerIface->getState<OSVR_PositionReport>(
                        timest, report.state.basePoint);
            }
            if (!(report.state.basePointValid || report.state.directionValid)) {
                return; // don't send an empty report.
            }

            /// @todo what timestamp do we use - the one from the notification
            /// or the ones from the original reports? At least right now
            /// they're theoretically the same, but...
            for (auto &iface : m_interfaces) {
                iface->triggerCallbacks(timestamp, report);
            }
        }

        void m_handleEyeTracking2d(common::OSVR_EyeNotification const &data,
                                   util::time::TimeValue const &timestamp) {

            OSVR_EyeTracker2DReport report;
            report.sensor = data.sensor;
            bool locationValid = false;
            util::time::TimeValue reportTime;

            if (m_opts.reportLocation2D) {
                locationValid =
                    m_opts.locationIface->getState<OSVR_Location2DReport>(
                        reportTime, report.state);
            }
            if (!locationValid) {
                return; // don't send an empty report.
            }

            /// @todo what timestamp do we use - the one from the notification
            /// or the one from the original report? At least right now they're
            /// the same, but...
            for (auto &iface : m_interfaces) {
                iface->triggerCallbacks(timestamp, report);
            }
        }

        void m_handleEyeBlink(common::OSVR_EyeNotification const &data,
                              util::time::TimeValue const &timestamp) {

            OSVR_EyeTrackerBlinkReport report;
            report.sensor = data.sensor;
            bool haveBlink = false;
            util::time::TimeValue blinkTimestamp;

            if (m_opts.reportLocation2D) {
                haveBlink = m_opts.locationIface->getState<OSVR_ButtonReport>(
                    blinkTimestamp, report.state);
            }
            if (!haveBlink) {
                return; // don't send an empty report.
            }
            /// @todo what timestamp do we use - the one from the notification
            /// or the one from the original report? At least right now they're
            /// the same, but...
            for (auto &iface : m_interfaces) {
                iface->triggerCallbacks(timestamp, report);
            }
        }

        void m_handleEyeTracking(common::OSVR_EyeNotification const &data,
                                 util::time::TimeValue const &timestamp) {
            if (!m_all && *m_sensor != data.sensor) {
                /// doesn't match our filter.
                return;
            }

            m_handleEyeTracking3d(data, timestamp);
            m_handleEyeTracking2d(data, timestamp);
            m_handleEyeBlink(data, timestamp);
        }

        common::BaseDevicePtr m_dev;
        common::InterfaceList &m_interfaces;
        bool m_all;
        Options m_opts;
        boost::optional<OSVR_ChannelCount> m_sensor;
    };

    EyeTrackerRemoteFactory::EyeTrackerRemoteFactory(
        VRPNConnectionCollection const &conns)
        : m_conns(conns) {}

    shared_ptr<RemoteHandler> EyeTrackerRemoteFactory::
    operator()(common::OriginalSource const &source,
               common::InterfaceList &ifaces, common::ClientContext &ctx) {

        shared_ptr<RemoteHandler> ret;

        NetworkEyeTrackerRemoteHandler::Options opts;

        auto myDescriptor = source.getDeviceElement().getDescriptor();

        if (myDescriptor["interfaces"]["eyetracker"].isMember("direction")) {
            opts.reportDirection = true;
            const std::string iface =
                common::getPathSeparator() +
                source.getDeviceElement().getDeviceName() + "/direction";
            /// @todo need to append sensor number here!
            // boost::lexical_cast<std::string>(source.getSensorNumberAsChannelCount())
            opts.dirIface = ctx.getInterface(iface.c_str());
        }
        if (myDescriptor["interfaces"]["eyetracker"].isMember("tracker")) {
            opts.reportBasePoint = true;
            const std::string iface =
                common::getPathSeparator() +
                source.getDeviceElement().getDeviceName() + "/tracker/";
            /// @todo need to append sensor number here!
            // boost::lexical_cast<std::string>(source.getSensorNumberAsChannelCount())
            opts.trackerIface = ctx.getInterface(iface.c_str());
        }

        if (myDescriptor["interfaces"]["eyetracker"].isMember("location2D")) {
            opts.reportLocation2D = true;
            const std::string iface =
                common::getPathSeparator() +
                source.getDeviceElement().getDeviceName() + "/location2D/";
            /// @todo need to append sensor number here!
            // boost::lexical_cast<std::string>(source.getSensorNumberAsChannelCount())
            opts.locationIface = ctx.getInterface(iface.c_str());
        }
        if (myDescriptor["interfaces"]["eyetracker"].isMember("button")) {
            opts.reportBlink = true;
            const std::string iface =
                common::getPathSeparator() +
                source.getDeviceElement().getDeviceName() + "/button/";
            /// @todo need to append sensor number here!
            // boost::lexical_cast<std::string>(source.getSensorNumberAsChannelCount())
            opts.buttonIface = ctx.getInterface(iface.c_str());
        }

        if (source.hasTransform()) {
            OSVR_DEV_VERBOSE(
                "Ignoring transform found on route for Eye Tracker data!");
        }

        auto const &devElt = source.getDeviceElement();

        ret.reset(new NetworkEyeTrackerRemoteHandler(
            m_conns.getConnection(devElt), devElt.getFullDeviceName(), opts,
            source.getSensorNumberAsChannelCount(), ifaces));
        return ret;
    }

} // namespace client
} // namespace osvr<commit_msg>Fix a copy-paste error.<commit_after>/** @file
    @brief Implementation

    @date 2015

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2015 Sensics, 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.

// Internal Includes
#include "EyeTrackerRemoteFactory.h"
#include "VRPNConnectionCollection.h"
#include <osvr/Common/ClientInterface.h>
#include <osvr/Common/PathTreeFull.h>
#include <osvr/Util/ChannelCountC.h>
#include <osvr/Util/UniquePtr.h>
#include <osvr/Common/OriginalSource.h>
#include "InterfaceTree.h"
#include <osvr/Util/Verbosity.h>
#include <osvr/Common/CreateDevice.h>

#include <osvr/Common/EyeTrackerComponent.h>
#include <osvr/Common/Location2DComponent.h>
#include <osvr/Common/DirectionComponent.h>
#include <osvr/Common/RoutingConstants.h>
#include <osvr/Common/InterfaceState.h>

// Library/third-party includes
#include <boost/lexical_cast.hpp>
#include <boost/any.hpp>
#include <boost/variant/get.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>
#include <json/value.h>
#include <json/reader.h>

// Standard includes
#include <iostream>
#include <string>

namespace osvr {
namespace client {

    class NetworkEyeTrackerRemoteHandler : public RemoteHandler {
      public:
        struct Options {
            Options()
                : reportDirection(false), reportBasePoint(false),
                  reportLocation2D(false), reportBlink(false), dirIface() {}
            bool reportDirection;
            bool reportBasePoint;
            bool reportLocation2D;
            bool reportBlink;
            osvr::common::ClientInterfacePtr dirIface;
            osvr::common::ClientInterfacePtr locationIface;
            osvr::common::ClientInterfacePtr trackerIface;
            osvr::common::ClientInterfacePtr buttonIface;
        };

        NetworkEyeTrackerRemoteHandler(
            vrpn_ConnectionPtr const &conn, std::string const &deviceName,
            Options const &options, boost::optional<OSVR_ChannelCount> sensor,
            common::InterfaceList &ifaces)
            : m_dev(common::createClientDevice(deviceName, conn)),
              m_interfaces(ifaces), m_all(!sensor.is_initialized()),
              m_opts(options), m_sensor(sensor) {
            auto eyetracker = common::EyeTrackerComponent::create();
            m_dev->addComponent(eyetracker);
            eyetracker->registerEyeHandler(
                [&](common::OSVR_EyeNotification const &data,
                    util::time::TimeValue const &timestamp) {
                    m_handleEyeTracking(data, timestamp);
                });
            OSVR_DEV_VERBOSE("Constructed an Eye Handler for " << deviceName);
        }

        /// @brief Deleted assignment operator.
        NetworkEyeTrackerRemoteHandler &
        operator=(NetworkEyeTrackerRemoteHandler const &) = delete;

        virtual ~NetworkEyeTrackerRemoteHandler() {
            /// @todo do we need to unregister?
        }

        virtual void update() { m_dev->update(); }

      private:
        void m_handleEyeTracking3d(common::OSVR_EyeNotification const &data,
                                   util::time::TimeValue const &timestamp) {

            OSVR_EyeTracker3DReport report;
            report.sensor = data.sensor;
            report.state.directionValid = false;
            report.state.basePointValid = false;
            util::time::TimeValue timest = timestamp;
            if (m_opts.reportDirection) {
                report.state.directionValid =
                    m_opts.dirIface->getState<OSVR_DirectionReport>(
                        timest, report.state.direction);
            }
            if (m_opts.reportBasePoint) {
                report.state.basePointValid =
                    m_opts.trackerIface->getState<OSVR_PositionReport>(
                        timest, report.state.basePoint);
            }
            if (!(report.state.basePointValid || report.state.directionValid)) {
                return; // don't send an empty report.
            }

            /// @todo what timestamp do we use - the one from the notification
            /// or the ones from the original reports? At least right now
            /// they're theoretically the same, but...
            for (auto &iface : m_interfaces) {
                iface->triggerCallbacks(timestamp, report);
            }
        }

        void m_handleEyeTracking2d(common::OSVR_EyeNotification const &data,
                                   util::time::TimeValue const &timestamp) {

            OSVR_EyeTracker2DReport report;
            report.sensor = data.sensor;
            bool locationValid = false;
            util::time::TimeValue reportTime;

            if (m_opts.reportLocation2D) {
                locationValid =
                    m_opts.locationIface->getState<OSVR_Location2DReport>(
                        reportTime, report.state);
            }
            if (!locationValid) {
                return; // don't send an empty report.
            }

            /// @todo what timestamp do we use - the one from the notification
            /// or the one from the original report? At least right now they're
            /// the same, but...
            for (auto &iface : m_interfaces) {
                iface->triggerCallbacks(timestamp, report);
            }
        }

        void m_handleEyeBlink(common::OSVR_EyeNotification const &data,
                              util::time::TimeValue const &timestamp) {

            OSVR_EyeTrackerBlinkReport report;
            report.sensor = data.sensor;
            bool haveBlink = false;
            util::time::TimeValue blinkTimestamp;

            if (m_opts.reportBlink) {
                haveBlink = m_opts.locationIface->getState<OSVR_ButtonReport>(
                    blinkTimestamp, report.state);
            }
            if (!haveBlink) {
                return; // don't send an empty report.
            }
            /// @todo what timestamp do we use - the one from the notification
            /// or the one from the original report? At least right now they're
            /// the same, but...
            for (auto &iface : m_interfaces) {
                iface->triggerCallbacks(timestamp, report);
            }
        }

        void m_handleEyeTracking(common::OSVR_EyeNotification const &data,
                                 util::time::TimeValue const &timestamp) {
            if (!m_all && *m_sensor != data.sensor) {
                /// doesn't match our filter.
                return;
            }

            m_handleEyeTracking3d(data, timestamp);
            m_handleEyeTracking2d(data, timestamp);
            m_handleEyeBlink(data, timestamp);
        }

        common::BaseDevicePtr m_dev;
        common::InterfaceList &m_interfaces;
        bool m_all;
        Options m_opts;
        boost::optional<OSVR_ChannelCount> m_sensor;
    };

    EyeTrackerRemoteFactory::EyeTrackerRemoteFactory(
        VRPNConnectionCollection const &conns)
        : m_conns(conns) {}

    shared_ptr<RemoteHandler> EyeTrackerRemoteFactory::
    operator()(common::OriginalSource const &source,
               common::InterfaceList &ifaces, common::ClientContext &ctx) {

        shared_ptr<RemoteHandler> ret;

        NetworkEyeTrackerRemoteHandler::Options opts;

        auto myDescriptor = source.getDeviceElement().getDescriptor();

        if (myDescriptor["interfaces"]["eyetracker"].isMember("direction")) {
            opts.reportDirection = true;
            const std::string iface =
                common::getPathSeparator() +
                source.getDeviceElement().getDeviceName() + "/direction";
            /// @todo need to append sensor number here!
            // boost::lexical_cast<std::string>(source.getSensorNumberAsChannelCount())
            opts.dirIface = ctx.getInterface(iface.c_str());
        }
        if (myDescriptor["interfaces"]["eyetracker"].isMember("tracker")) {
            opts.reportBasePoint = true;
            const std::string iface =
                common::getPathSeparator() +
                source.getDeviceElement().getDeviceName() + "/tracker/";
            /// @todo need to append sensor number here!
            // boost::lexical_cast<std::string>(source.getSensorNumberAsChannelCount())
            opts.trackerIface = ctx.getInterface(iface.c_str());
        }

        if (myDescriptor["interfaces"]["eyetracker"].isMember("location2D")) {
            opts.reportLocation2D = true;
            const std::string iface =
                common::getPathSeparator() +
                source.getDeviceElement().getDeviceName() + "/location2D/";
            /// @todo need to append sensor number here!
            // boost::lexical_cast<std::string>(source.getSensorNumberAsChannelCount())
            opts.locationIface = ctx.getInterface(iface.c_str());
        }
        if (myDescriptor["interfaces"]["eyetracker"].isMember("button")) {
            opts.reportBlink = true;
            const std::string iface =
                common::getPathSeparator() +
                source.getDeviceElement().getDeviceName() + "/button/";
            /// @todo need to append sensor number here!
            // boost::lexical_cast<std::string>(source.getSensorNumberAsChannelCount())
            opts.buttonIface = ctx.getInterface(iface.c_str());
        }

        if (source.hasTransform()) {
            OSVR_DEV_VERBOSE(
                "Ignoring transform found on route for Eye Tracker data!");
        }

        auto const &devElt = source.getDeviceElement();

        ret.reset(new NetworkEyeTrackerRemoteHandler(
            m_conns.getConnection(devElt), devElt.getFullDeviceName(), opts,
            source.getSensorNumberAsChannelCount(), ifaces));
        return ret;
    }

} // namespace client
} // namespace osvr<|endoftext|>


<commit_before>/**
 * This file is part of the KDE project
 *
 * Copyright (C) 2001,2003 Peter Kelly (pmk@post.com)
 * Copyright (C) 2003,2004 Stephan Kulow (coolo@kde.org)
 * Copyright (C) 2004 Dirk Mueller ( mueller@kde.org )
 * Copyright 2006, 2007 Leo Savernik (l.savernik@aon.at)
 * Copyright (C) 2010 Milian Wolff <mail@milianw.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */

//BEGIN Includes
#include "indenttest.h"

#include "kateview.h"
#include "katedocument.h"
#include "katedocumenthelpers.h"
#include "kateconfig.h"
#include "katecmd.h"
#include "kateglobal.h"
#include <ktexteditor/commandinterface.h>

#include <kapplication.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kaction.h>
#include <kcmdlineargs.h>
#include <kmainwindow.h>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <kglobalsettings.h>
#include <kdefakes.h>
#include <kstatusbar.h>
#include <kio/job.h>

#include <memory>
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <limits.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pwd.h>
#include <signal.h>

#include <QtCore/QObject>
#include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/QString>
#include <QtCore/QRegExp>
#include <QtCore/QTextStream>
#include <QtCore/QList>
#include <QtCore/QTimer>
#include <QtCore/QFileInfo>
#include <QtCore/Q_PID>
#include <QtCore/QEvent>
#include <QtCore/QTimer>
#include <QtCore/QFileInfo>

#include <QtScript/QScriptEngine>
#include <QTest>
#include <qtest_kde.h>

#include "testutils.h"

QTEST_KDEMAIN(IndentTest, GUI)

/// somepath/part/tests/
const QString srcPath(KDESRCDIR);

#define FAILURE( test, comment ) qMakePair<const char*, const char*>( (test), (comment) )

void IndentTest::initTestCase()
{
  m_toplevel = new KMainWindow();
  m_document = new KateDocument(true, false, false, m_toplevel);
  m_view = static_cast<KateView *>(m_document->widget());
  m_env = new TestScriptEnv(m_document, m_outputCustomised);
}

void IndentTest::cleanupTestCase()
{
}

void IndentTest::getTestData(const QString& indenter)
{
  QTest::addColumn<QString>("testcase");

  const QString testDir( srcPath + "/../../testdata/indent/" + indenter + '/' );
  Q_ASSERT( QFile::exists(testDir) );
  QDirIterator contents( testDir );
  while ( contents.hasNext() ) {
    QString entry = contents.next();
    if ( entry.endsWith('.') ) {
      continue;
    }
    QFileInfo info(entry);
    if ( !info.isDir() ) {
      continue;
    }
    QTest::newRow( info.baseName().toLocal8Bit() ) << info.absoluteFilePath();
  }
}

void IndentTest::runTest(const ExpectedFailures& failures)
{
  QFETCH(QString, testcase);

  m_toplevel->resize( 800, 600); // restore size

  // load page
  KUrl url;
  url.setProtocol("file");
  url.setPath(testcase + "/origin");
  m_document->openUrl(url);

  // evaluate test-script
  QFile sourceFile(testcase + "/input.js");
  QVERIFY( sourceFile.open(QFile::ReadOnly) );

  QTextStream stream(&sourceFile);
  stream.setCodec("UTF8");
  QString code = stream.readAll();
  sourceFile.close();

  // Execute script
  QScriptValue result = m_env->engine()->evaluate(code, testcase + "/input.js", 1);
  QVERIFY2( !result.isError(), result.toString().toUtf8().constData() );

  url.setPath(testcase + "/actual");
  m_document->saveAs(url);

  // diff actual and expected
  QProcess diff;
  QStringList args;
  args << "-u" << (testcase + "/expected") << (testcase + "/actual");
  diff.start("diff", args);
  diff.waitForFinished();
  QByteArray out = diff.readAllStandardOutput();
  QByteArray err = diff.readAllStandardError();
  if ( !err.isEmpty() ) {
    qWarning() << err;
  }
  foreach( const Failure& failure, failures ) {
    QEXPECT_FAIL(failure.first, failure.second, Abort);
  }
  QCOMPARE(QString::fromLocal8Bit(out), QString());
  QCOMPARE(diff.exitCode(), EXIT_SUCCESS);

  m_document->closeUrl();
}

void IndentTest::cstyle_data()
{
  getTestData( "cstyle" );
}

void IndentTest::cstyle()
{
  runTest( ExpectedFailures() << FAILURE( "using1", "this is insane, those who write such code can cope with it :P" )
                              << FAILURE( "using2", "this is insane, those who write such code can cope with it :P" )
                              << FAILURE( "plist14", "in function signatures it might be wanted to use the indentation of the\n"
                                                     "opening paren instead of just increasing the indentation level like in function calls" )
                              << FAILURE( "switch10", "test for case where cfgSwitchIndent = false; needs proper config-interface" )
                              << FAILURE( "switch11", "test for case where cfgSwitchIndent = false; needs proper config-interface" )
                              << FAILURE( "visib2", "test for access modifier where cfgAccessModifiers = 1;needs proper config interface" )
                              << FAILURE( "visib3", "test for access modifier where cfgAccessModifiers = 1;needs proper config interface" )
                              << FAILURE( "plist10", "low low prio, maybe wontfix: if the user wants to add a arg, he should do so and press enter afterwards" )
  );
}

void IndentTest::haskell_data()
{
  getTestData( "haskell" );
}

void IndentTest::haskell()
{
  runTest( ExpectedFailures() );
}

void IndentTest::ruby_data()
{
  getTestData( "ruby" );
}

void IndentTest::ruby()
{
  runTest( ExpectedFailures() << FAILURE( "block01", "Multiline blocks using {} is not supported" )
                              << FAILURE( "block02", "Multiline blocks using {} is not supported" )
  );
}

void IndentTest::normal_data()
{
  getTestData( "normal" );
}

void IndentTest::normal()
{
  runTest( ExpectedFailures() << FAILURE( "emptyline1", "is that really what we expect?" )
                              << FAILURE( "emptyline3", "is that really what we expext?" )
  );
}
<commit_msg>mwolff:     expect yet another failure for an insane corner case, no need to fix it<commit_after>/**
 * This file is part of the KDE project
 *
 * Copyright (C) 2001,2003 Peter Kelly (pmk@post.com)
 * Copyright (C) 2003,2004 Stephan Kulow (coolo@kde.org)
 * Copyright (C) 2004 Dirk Mueller ( mueller@kde.org )
 * Copyright 2006, 2007 Leo Savernik (l.savernik@aon.at)
 * Copyright (C) 2010 Milian Wolff <mail@milianw.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */

//BEGIN Includes
#include "indenttest.h"

#include "kateview.h"
#include "katedocument.h"
#include "katedocumenthelpers.h"
#include "kateconfig.h"
#include "katecmd.h"
#include "kateglobal.h"
#include <ktexteditor/commandinterface.h>

#include <kapplication.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kaction.h>
#include <kcmdlineargs.h>
#include <kmainwindow.h>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <kglobalsettings.h>
#include <kdefakes.h>
#include <kstatusbar.h>
#include <kio/job.h>

#include <memory>
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <limits.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pwd.h>
#include <signal.h>

#include <QtCore/QObject>
#include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/QString>
#include <QtCore/QRegExp>
#include <QtCore/QTextStream>
#include <QtCore/QList>
#include <QtCore/QTimer>
#include <QtCore/QFileInfo>
#include <QtCore/Q_PID>
#include <QtCore/QEvent>
#include <QtCore/QTimer>
#include <QtCore/QFileInfo>

#include <QtScript/QScriptEngine>
#include <QTest>
#include <qtest_kde.h>

#include "testutils.h"

QTEST_KDEMAIN(IndentTest, GUI)

/// somepath/part/tests/
const QString srcPath(KDESRCDIR);

#define FAILURE( test, comment ) qMakePair<const char*, const char*>( (test), (comment) )

void IndentTest::initTestCase()
{
  m_toplevel = new KMainWindow();
  m_document = new KateDocument(true, false, false, m_toplevel);
  m_view = static_cast<KateView *>(m_document->widget());
  m_env = new TestScriptEnv(m_document, m_outputCustomised);
}

void IndentTest::cleanupTestCase()
{
}

void IndentTest::getTestData(const QString& indenter)
{
  QTest::addColumn<QString>("testcase");

  const QString testDir( srcPath + "/../../testdata/indent/" + indenter + '/' );
  Q_ASSERT( QFile::exists(testDir) );
  QDirIterator contents( testDir );
  while ( contents.hasNext() ) {
    QString entry = contents.next();
    if ( entry.endsWith('.') ) {
      continue;
    }
    QFileInfo info(entry);
    if ( !info.isDir() ) {
      continue;
    }
    QTest::newRow( info.baseName().toLocal8Bit() ) << info.absoluteFilePath();
  }
}

void IndentTest::runTest(const ExpectedFailures& failures)
{
  QFETCH(QString, testcase);

  m_toplevel->resize( 800, 600); // restore size

  // load page
  KUrl url;
  url.setProtocol("file");
  url.setPath(testcase + "/origin");
  m_document->openUrl(url);

  // evaluate test-script
  QFile sourceFile(testcase + "/input.js");
  QVERIFY( sourceFile.open(QFile::ReadOnly) );

  QTextStream stream(&sourceFile);
  stream.setCodec("UTF8");
  QString code = stream.readAll();
  sourceFile.close();

  // Execute script
  QScriptValue result = m_env->engine()->evaluate(code, testcase + "/input.js", 1);
  QVERIFY2( !result.isError(), result.toString().toUtf8().constData() );

  url.setPath(testcase + "/actual");
  m_document->saveAs(url);

  // diff actual and expected
  QProcess diff;
  QStringList args;
  args << "-u" << (testcase + "/expected") << (testcase + "/actual");
  diff.start("diff", args);
  diff.waitForFinished();
  QByteArray out = diff.readAllStandardOutput();
  QByteArray err = diff.readAllStandardError();
  if ( !err.isEmpty() ) {
    qWarning() << err;
  }
  foreach( const Failure& failure, failures ) {
    QEXPECT_FAIL(failure.first, failure.second, Abort);
  }
  QCOMPARE(QString::fromLocal8Bit(out), QString());
  QCOMPARE(diff.exitCode(), EXIT_SUCCESS);

  m_document->closeUrl();
}

void IndentTest::cstyle_data()
{
  getTestData( "cstyle" );
}

void IndentTest::cstyle()
{
  runTest( ExpectedFailures() << FAILURE( "using1", "this is insane, those who write such code can cope with it :P" )
                              << FAILURE( "using2", "this is insane, those who write such code can cope with it :P" )
                              << FAILURE( "plist14", "in function signatures it might be wanted to use the indentation of the\n"
                                                     "opening paren instead of just increasing the indentation level like in function calls" )
                              << FAILURE( "switch10", "test for case where cfgSwitchIndent = false; needs proper config-interface" )
                              << FAILURE( "switch11", "test for case where cfgSwitchIndent = false; needs proper config-interface" )
                              << FAILURE( "visib2", "test for access modifier where cfgAccessModifiers = 1;needs proper config interface" )
                              << FAILURE( "visib3", "test for access modifier where cfgAccessModifiers = 1;needs proper config interface" )
                              << FAILURE( "plist10", "low low prio, maybe wontfix: if the user wants to add a arg, he should do so and press enter afterwards" )
                              << FAILURE( "switch13", "pure insanity, whoever wrote this test and expects that to be indented properly should stop writing code" )
  );
}

void IndentTest::haskell_data()
{
  getTestData( "haskell" );
}

void IndentTest::haskell()
{
  runTest( ExpectedFailures() );
}

void IndentTest::ruby_data()
{
  getTestData( "ruby" );
}

void IndentTest::ruby()
{
  runTest( ExpectedFailures() << FAILURE( "block01", "Multiline blocks using {} is not supported" )
                              << FAILURE( "block02", "Multiline blocks using {} is not supported" )
  );
}

void IndentTest::normal_data()
{
  getTestData( "normal" );
}

void IndentTest::normal()
{
  runTest( ExpectedFailures() << FAILURE( "emptyline1", "is that really what we expect?" )
                              << FAILURE( "emptyline3", "is that really what we expext?" )
  );
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <Log.h>
#include <vfs/VFS.h>
#include <ext2/Ext2Filesystem.h>
#include <machine/Device.h>
#include <machine/Disk.h>
#include <Module.h>
#include <processor/Processor.h>
#include <linker/Elf.h>
#include <process/Thread.h>
#include <process/Process.h>
#include <process/Scheduler.h>
#include <processor/PhysicalMemoryManager.h>
#include <processor/VirtualAddressSpace.h>
#include <machine/Machine.h>
#include <linker/DynamicLinker.h>
#include <panic.h>
#include "../../kernel/core/BootIO.h"

#include <network/NetworkStack.h>
#include <network/RoutingTable.h>

extern BootIO bootIO;

static bool probeDisk(Disk *pDisk)
{
  String alias; // Null - gets assigned by the filesystem.
  if (VFS::instance().mount(pDisk, alias))
  {
    // search for the root specifier
    NormalStaticString s;
    s += alias;
    s += ":/.pedigree-root";

    File* f = VFS::instance().find(String(static_cast<const char*>(s)));
    if(f)
    {
      if(f->isValid())
      {
        NOTICE("Mounted " << alias << " successfully as root.");
        VFS::instance().addAlias(alias, String("root"));
      }
    delete f;
    }
    else
    {
      NOTICE("Mounted " << alias << ".");
    }
    return false;
  }
  return false;
}

static bool findDisks(Device *pDev)
{
  for (unsigned int i = 0; i < pDev->getNumChildren(); i++)
  {
    Device *pChild = pDev->getChild(i);
    if (pChild->getNumChildren() == 0 && /* Only check leaf nodes. */
        pChild->getType() == Device::Disk)
    {
      if ( probeDisk(static_cast<Disk*> (pChild)) ) return true;
    }
    else
    {
      // Recurse.
      if (findDisks(pChild)) return true;
    }
  }
  return false;
}

void init()
{
  static HugeStaticString str;

  // Mount all available filesystems.
  if (!findDisks(&Device::root()))
  {
//     FATAL("No disks found!");
  }

  // Build routing tables
  File* routeConfig = VFS::instance().find(String("root:/config/routes"));
  if(routeConfig->isValid())
  {
    NOTICE("Loading route table from file");
    /// \todo Write this...
  }
  else
  {
    // try to find a default configuration that can connect to the outside world
    bool bRouteFound = false;
    for(size_t i = 0; i < NetworkStack::instance().getNumDevices(); i++)
    {
      /// \todo Perhaps try and ping a remote host?
      Network* card = NetworkStack::instance().getDevice(i);
      StationInfo info = card->getStationInfo();
      if(!(info.gateway == 0)) /// \todo write operator !=
      {
        RoutingTable::instance().AddNamed(String("default"), card);
        bRouteFound = true;
        break;
      }
    }

    // otherwise, just assume the default is interface zero
    if(!bRouteFound)
      RoutingTable::instance().AddNamed(String("default"), NetworkStack::instance().getDevice(0));
  }

  HugeStaticString str;
  str += "Loading init program (root:/applications/bash)\n";
  bootIO.write(str, BootIO::White, BootIO::Black);
  str.clear();

  // Load initial program.
  File* initProg = VFS::instance().find(String("root:/applications/bash"));
  if (!initProg->isValid())
  {
    FATAL("Unable to load init program!");
    return;
  }

  uint8_t *buffer = new uint8_t[initProg->getSize()];
  initProg->read(0, initProg->getSize(), reinterpret_cast<uintptr_t>(buffer));

  Machine::instance().getKeyboard()->setDebugState(false);

  // At this point we're uninterruptible, as we're forking.
  Spinlock lock;
  lock.acquire();

  // Create a new process for the init process.
  Process *pProcess = new Process(Processor::information().getCurrentThread()->getParent());

  pProcess->description().clear();
  pProcess->description().append("init");

  VirtualAddressSpace &oldAS = Processor::information().getVirtualAddressSpace();

  // Switch to the init process' address space.
  Processor::switchAddressSpace(*pProcess->getAddressSpace());

  // That will have forked - we don't want to fork, so clear out all the chaff in the new address space that's not
  // in the kernel address space so we have a clean slate.
  pProcess->getAddressSpace()->revertToKernelAddressSpace();

  static Elf initElf;
  uintptr_t loadBase;

  initElf.create(buffer, initProg->getSize());
  initElf.allocate(buffer, initProg->getSize(), loadBase, 0, pProcess);

  DynamicLinker::instance().setInitProcess(pProcess);
  NOTICE("regElf");
  DynamicLinker::instance().registerElf(&initElf);
NOTICE("needed");
  uintptr_t iter = 0;
  List<char*> neededLibraries = initElf.neededLibraries();
  for (List<char*>::Iterator it = neededLibraries.begin();
       it != neededLibraries.end();
       it++)
  {
    NOTICE("n1");
    if (!DynamicLinker::instance().load(*it, pProcess))
    {
      ERROR("Couldn't open needed file '" << *it << "'");
      FATAL("Init program failed to load!");
      return;
    }
    NOTICE("n2");
  }
NOTICE("bleh");
  initElf.load(buffer, initProg->getSize(), loadBase, initElf.getSymbolTable());
  DynamicLinker::instance().initialiseElf(&initElf);
  DynamicLinker::instance().setInitProcess(0);
  ERROR("Init elf: " << (uintptr_t)&initElf);
  for (int j = 0; j < 0x20000; j += 0x1000)
  {
    physical_uintptr_t phys = PhysicalMemoryManager::instance().allocatePage();
    bool b = Processor::information().getVirtualAddressSpace().map(phys,
                                                                   reinterpret_cast<void*> (j+0x20000000),
                                                                   VirtualAddressSpace::Write);
    if (!b)
      WARNING("map() failed in init");
  }

  // Alrighty - lets create a new thread for this program - -8 as PPC assumes the previous stack frame is available...
  Thread *pThread = new Thread(pProcess, reinterpret_cast<Thread::ThreadStartFunc>(initElf.getEntryPoint()), 0x0 /* parameter */,  reinterpret_cast<void*>(0x20020000-8) /* Stack */);

  // Switch back to the old address space.
  Processor::switchAddressSpace(oldAS);

  delete [] buffer;

  delete initProg;

  lock.release();

}

void destroy()
{
}

MODULE_NAME("init");
MODULE_ENTRY(&init);
MODULE_EXIT(&destroy);
#ifdef X86_COMMON
MODULE_DEPENDS("VFS", "ext2", "posix", "partition", "TUI", "linker", "vbe", "NetworkStack");
#elif PPC_COMMON
MODULE_DEPENDS("VFS", "ext2", "posix", "partition", "TUI", "linker", "NetworkStack");
#endif

<commit_msg>Removing redeclaration of variable caused by SVN conflict in init module<commit_after>/*
 * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <Log.h>
#include <vfs/VFS.h>
#include <ext2/Ext2Filesystem.h>
#include <machine/Device.h>
#include <machine/Disk.h>
#include <Module.h>
#include <processor/Processor.h>
#include <linker/Elf.h>
#include <process/Thread.h>
#include <process/Process.h>
#include <process/Scheduler.h>
#include <processor/PhysicalMemoryManager.h>
#include <processor/VirtualAddressSpace.h>
#include <machine/Machine.h>
#include <linker/DynamicLinker.h>
#include <panic.h>
#include "../../kernel/core/BootIO.h"

#include <network/NetworkStack.h>
#include <network/RoutingTable.h>

extern BootIO bootIO;

static bool probeDisk(Disk *pDisk)
{
  String alias; // Null - gets assigned by the filesystem.
  if (VFS::instance().mount(pDisk, alias))
  {
    // search for the root specifier
    NormalStaticString s;
    s += alias;
    s += ":/.pedigree-root";

    File* f = VFS::instance().find(String(static_cast<const char*>(s)));
    if(f)
    {
      if(f->isValid())
      {
        NOTICE("Mounted " << alias << " successfully as root.");
        VFS::instance().addAlias(alias, String("root"));
      }
    delete f;
    }
    else
    {
      NOTICE("Mounted " << alias << ".");
    }
    return false;
  }
  return false;
}

static bool findDisks(Device *pDev)
{
  for (unsigned int i = 0; i < pDev->getNumChildren(); i++)
  {
    Device *pChild = pDev->getChild(i);
    if (pChild->getNumChildren() == 0 && /* Only check leaf nodes. */
        pChild->getType() == Device::Disk)
    {
      if ( probeDisk(static_cast<Disk*> (pChild)) ) return true;
    }
    else
    {
      // Recurse.
      if (findDisks(pChild)) return true;
    }
  }
  return false;
}

void init()
{
  static HugeStaticString str;

  // Mount all available filesystems.
  if (!findDisks(&Device::root()))
  {
//     FATAL("No disks found!");
  }

  // Build routing tables
  File* routeConfig = VFS::instance().find(String("root:/config/routes"));
  if(routeConfig->isValid())
  {
    NOTICE("Loading route table from file");
    /// \todo Write this...
  }
  else
  {
    // try to find a default configuration that can connect to the outside world
    bool bRouteFound = false;
    for(size_t i = 0; i < NetworkStack::instance().getNumDevices(); i++)
    {
      /// \todo Perhaps try and ping a remote host?
      Network* card = NetworkStack::instance().getDevice(i);
      StationInfo info = card->getStationInfo();
      if(!(info.gateway == 0)) /// \todo write operator !=
      {
        RoutingTable::instance().AddNamed(String("default"), card);
        bRouteFound = true;
        break;
      }
    }

    // otherwise, just assume the default is interface zero
    if(!bRouteFound)
      RoutingTable::instance().AddNamed(String("default"), NetworkStack::instance().getDevice(0));
  }

  str += "Loading init program (root:/applications/bash)\n";
  bootIO.write(str, BootIO::White, BootIO::Black);
  str.clear();

  // Load initial program.
  File* initProg = VFS::instance().find(String("root:/applications/bash"));
  if (!initProg->isValid())
  {
    FATAL("Unable to load init program!");
    return;
  }

  uint8_t *buffer = new uint8_t[initProg->getSize()];
  initProg->read(0, initProg->getSize(), reinterpret_cast<uintptr_t>(buffer));

  Machine::instance().getKeyboard()->setDebugState(false);

  // At this point we're uninterruptible, as we're forking.
  Spinlock lock;
  lock.acquire();

  // Create a new process for the init process.
  Process *pProcess = new Process(Processor::information().getCurrentThread()->getParent());

  pProcess->description().clear();
  pProcess->description().append("init");

  VirtualAddressSpace &oldAS = Processor::information().getVirtualAddressSpace();

  // Switch to the init process' address space.
  Processor::switchAddressSpace(*pProcess->getAddressSpace());

  // That will have forked - we don't want to fork, so clear out all the chaff in the new address space that's not
  // in the kernel address space so we have a clean slate.
  pProcess->getAddressSpace()->revertToKernelAddressSpace();

  static Elf initElf;
  uintptr_t loadBase;

  initElf.create(buffer, initProg->getSize());
  initElf.allocate(buffer, initProg->getSize(), loadBase, 0, pProcess);

  DynamicLinker::instance().setInitProcess(pProcess);
  NOTICE("regElf");
  DynamicLinker::instance().registerElf(&initElf);
NOTICE("needed");
  uintptr_t iter = 0;
  List<char*> neededLibraries = initElf.neededLibraries();
  for (List<char*>::Iterator it = neededLibraries.begin();
       it != neededLibraries.end();
       it++)
  {
    NOTICE("n1");
    if (!DynamicLinker::instance().load(*it, pProcess))
    {
      ERROR("Couldn't open needed file '" << *it << "'");
      FATAL("Init program failed to load!");
      return;
    }
    NOTICE("n2");
  }
NOTICE("bleh");
  initElf.load(buffer, initProg->getSize(), loadBase, initElf.getSymbolTable());
  DynamicLinker::instance().initialiseElf(&initElf);
  DynamicLinker::instance().setInitProcess(0);
  ERROR("Init elf: " << (uintptr_t)&initElf);
  for (int j = 0; j < 0x20000; j += 0x1000)
  {
    physical_uintptr_t phys = PhysicalMemoryManager::instance().allocatePage();
    bool b = Processor::information().getVirtualAddressSpace().map(phys,
                                                                   reinterpret_cast<void*> (j+0x20000000),
                                                                   VirtualAddressSpace::Write);
    if (!b)
      WARNING("map() failed in init");
  }

  // Alrighty - lets create a new thread for this program - -8 as PPC assumes the previous stack frame is available...
  Thread *pThread = new Thread(pProcess, reinterpret_cast<Thread::ThreadStartFunc>(initElf.getEntryPoint()), 0x0 /* parameter */,  reinterpret_cast<void*>(0x20020000-8) /* Stack */);

  // Switch back to the old address space.
  Processor::switchAddressSpace(oldAS);

  delete [] buffer;

  delete initProg;

  lock.release();

}

void destroy()
{
}

MODULE_NAME("init");
MODULE_ENTRY(&init);
MODULE_EXIT(&destroy);
#ifdef X86_COMMON
MODULE_DEPENDS("VFS", "ext2", "posix", "partition", "TUI", "linker", "vbe", "NetworkStack");
#elif PPC_COMMON
MODULE_DEPENDS("VFS", "ext2", "posix", "partition", "TUI", "linker", "NetworkStack");
#endif

<|endoftext|>


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

#include "gerritpushdialog.h"
#include "ui_gerritpushdialog.h"

#include "../gitplugin.h"
#include "../gitclient.h"

#include <QDateTime>
#include <QDir>
#include <QRegExpValidator>

namespace Gerrit {
namespace Internal {

GerritPushDialog::GerritPushDialog(const QString &workingDir, const QString &reviewerList, QWidget *parent) :
    QDialog(parent),
    m_workingDir(workingDir),
    m_ui(new Ui::GerritPushDialog),
    m_localChangesFound(false),
    m_valid(false)
{
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
    m_ui->setupUi(this);
    m_ui->repositoryLabel->setText(tr("Local repository: %1").arg(
                                       QDir::toNativeSeparators(workingDir)));

    if (!m_ui->commitView->init(workingDir, QString(), false))
        return;

    QString earliestCommit = m_ui->commitView->earliestCommit();
    if (earliestCommit.isEmpty())
        return;

    m_localChangesFound = true;

    Git::Internal::GitClient *gitClient = Git::Internal::GitPlugin::instance()->gitClient();
    QString output;
    QString error;
    QStringList args;
    args << QLatin1String("-r") << QLatin1String("--contains")
         << earliestCommit + QLatin1Char('^');

    if (!gitClient->synchronousBranchCmd(m_workingDir, args, &output, &error))
        return;

    QString head = QLatin1String("/HEAD");
    QStringList refs = output.split(QLatin1Char('\n'));
    QString remoteTrackingBranch = gitClient->synchronousTrackingBranch(m_workingDir);
    QString remoteBranch;
    foreach (const QString &reference, refs) {
        const QString ref = reference.trimmed();
        if (ref.contains(head) || ref.isEmpty())
            continue;

        remoteBranch = ref;

        // Prefer remote tracking branch if it exists and contains the latest remote commit
        if (ref == remoteTrackingBranch)
            break;
    }

    if (!remoteBranch.isEmpty()) {
        m_suggestedRemoteName = remoteBranch.left(remoteBranch.indexOf(QLatin1Char('/')));
        m_suggestedRemoteBranch = remoteBranch.mid(remoteBranch.indexOf(QLatin1Char('/')) + 1);
    }

    output.clear();
    error.clear();
    args.clear();

    QString remotesPrefix(QLatin1String("refs/remotes/"));
    args << QLatin1String("--format=%(refname)\t%(committerdate:raw)")
         << remotesPrefix;
    if (!gitClient->synchronousForEachRefCmd(workingDir, args, &output))
        return;

    refs.clear();
    refs = output.split(QLatin1String("\n"));
    foreach (const QString &reference, refs) {
        QStringList entries = reference.split(QLatin1Char('\t'));
        if (entries.count() < 2 || entries.first().endsWith(head))
            continue;
        const QString ref = entries.at(0).mid(remotesPrefix.size());
        int refBranchIndex = ref.indexOf(QLatin1Char('/'));
        int timeT = entries.at(1).left(entries.at(1).indexOf(QLatin1Char(' '))).toInt();
        BranchDate bd(ref.mid(refBranchIndex + 1), QDateTime::fromTime_t(timeT).date());
        m_remoteBranches.insertMulti(ref.left(refBranchIndex), bd);
    }

    int currIndex = 0;
    QStringList remotes = m_remoteBranches.keys();
    remotes.removeDuplicates();
    foreach (const QString &remote, remotes) {
        m_ui->remoteComboBox->addItem(remote);
        if (remote == m_suggestedRemoteName)
            m_ui->remoteComboBox->setCurrentIndex(currIndex);
        ++currIndex;
    }
    const int remoteCount = m_ui->remoteComboBox->count();
    if (remoteCount < 1) {
        return;
    } else if (remoteCount == 1) {
        m_ui->remoteLabel->hide();
        m_ui->remoteComboBox->hide();
    } else {
        connect(m_ui->remoteComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setRemoteBranches()));
    }
    connect(m_ui->branchComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setChangeRange()));
    setRemoteBranches();
    m_ui->reviewersLineEdit->setText(reviewerList);

    m_ui->topicLineEdit->setValidator(new QRegExpValidator(QRegExp(QLatin1String("^\\S+$")), this));

    m_valid = true;
}

GerritPushDialog::~GerritPushDialog()
{
    delete m_ui;
}

QString GerritPushDialog::selectedCommit() const
{
    return m_ui->commitView->commit();
}

QString GerritPushDialog::calculateChangeRange()
{
    QString remote = selectedRemoteName();
    remote += QLatin1Char('/');
    remote += selectedRemoteBranchName();

    QStringList args(remote + QLatin1String("..HEAD"));
    args << QLatin1String("--count");

    QString number;

    if (!Git::Internal::GitPlugin::instance()->gitClient()->
            synchronousRevListCmd(m_workingDir, args, &number))
        reject();

    number.chop(1);
    return number;
}

void GerritPushDialog::setChangeRange()
{
    if (m_ui->branchComboBox->itemData(m_ui->branchComboBox->currentIndex()) == 1) {
        setRemoteBranches(true);
        return;
    }
    QString remote = selectedRemoteName();
    remote += QLatin1Char('/');
    remote += selectedRemoteBranchName();
    m_ui->infoLabel->setText(tr("Number of commits between HEAD and %1: %2").arg(
                                 remote, calculateChangeRange()));
}

bool GerritPushDialog::localChangesFound() const
{
    return m_localChangesFound;
}

bool GerritPushDialog::valid() const
{
    return m_valid;
}

void GerritPushDialog::setRemoteBranches(bool includeOld)
{
    bool blocked = m_ui->branchComboBox->blockSignals(true);
    m_ui->branchComboBox->clear();

    int i = 0;
    bool excluded = false;
    for (RemoteBranchesMap::const_iterator it = m_remoteBranches.constBegin(),
         end = m_remoteBranches.constEnd();
         it != end; ++it) {
        if (it.key() == selectedRemoteName()) {
            const BranchDate &bd = it.value();
            const bool isSuggested = bd.first == m_suggestedRemoteBranch;
            if (includeOld || bd.second.daysTo(QDate::currentDate()) <= 60 || isSuggested) {
                m_ui->branchComboBox->addItem(bd.first);
                if (isSuggested)
                    m_ui->branchComboBox->setCurrentIndex(i);
                ++i;
            } else {
                excluded = true;
            }
        }
    }
    if (excluded)
        m_ui->branchComboBox->addItem(tr("... Include older branches ..."), 1);
    setChangeRange();
    m_ui->branchComboBox->blockSignals(blocked);
}

QString GerritPushDialog::selectedRemoteName() const
{
    return m_ui->remoteComboBox->currentText();
}

QString GerritPushDialog::selectedRemoteBranchName() const
{
    return m_ui->branchComboBox->currentText();
}

QString GerritPushDialog::selectedPushType() const
{
    return m_ui->draftCheckBox->isChecked() ? QLatin1String("draft") : QLatin1String("for");
}

QString GerritPushDialog::selectedTopic() const
{
    return m_ui->topicLineEdit->text().trimmed();
}

QString GerritPushDialog::reviewers() const
{
    return m_ui->reviewersLineEdit->text();
}

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

#include "gerritpushdialog.h"
#include "ui_gerritpushdialog.h"

#include "../gitplugin.h"
#include "../gitclient.h"

#include <QDateTime>
#include <QDir>
#include <QRegExpValidator>

namespace Gerrit {
namespace Internal {

GerritPushDialog::GerritPushDialog(const QString &workingDir, const QString &reviewerList, QWidget *parent) :
    QDialog(parent),
    m_workingDir(workingDir),
    m_ui(new Ui::GerritPushDialog),
    m_localChangesFound(false),
    m_valid(false)
{
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
    m_ui->setupUi(this);
    m_ui->repositoryLabel->setText(tr("Local repository: %1").arg(
                                       QDir::toNativeSeparators(workingDir)));

    if (!m_ui->commitView->init(workingDir, QString(), false))
        return;

    QString earliestCommit = m_ui->commitView->earliestCommit();
    if (earliestCommit.isEmpty())
        return;

    m_localChangesFound = true;

    Git::Internal::GitClient *gitClient = Git::Internal::GitPlugin::instance()->gitClient();
    QString output;
    QString error;
    QStringList args;
    args << QLatin1String("-r") << QLatin1String("--contains")
         << earliestCommit + QLatin1Char('^');

    if (!gitClient->synchronousBranchCmd(m_workingDir, args, &output, &error))
        return;

    QString head = QLatin1String("/HEAD");
    QStringList refs = output.split(QLatin1Char('\n'));
    QString remoteTrackingBranch = gitClient->synchronousTrackingBranch(m_workingDir);
    QString remoteBranch;
    foreach (const QString &reference, refs) {
        const QString ref = reference.trimmed();
        if (ref.contains(head) || ref.isEmpty())
            continue;

        if (remoteBranch.isEmpty())
            remoteBranch = ref;

        // Prefer remote tracking branch if it exists and contains the latest remote commit
        if (ref == remoteTrackingBranch) {
            remoteBranch = ref;
            break;
        }
    }

    if (!remoteBranch.isEmpty()) {
        m_suggestedRemoteName = remoteBranch.left(remoteBranch.indexOf(QLatin1Char('/')));
        m_suggestedRemoteBranch = remoteBranch.mid(remoteBranch.indexOf(QLatin1Char('/')) + 1);
    }

    output.clear();
    error.clear();
    args.clear();

    QString remotesPrefix(QLatin1String("refs/remotes/"));
    args << QLatin1String("--format=%(refname)\t%(committerdate:raw)")
         << remotesPrefix;
    if (!gitClient->synchronousForEachRefCmd(workingDir, args, &output))
        return;

    refs.clear();
    refs = output.split(QLatin1String("\n"));
    foreach (const QString &reference, refs) {
        QStringList entries = reference.split(QLatin1Char('\t'));
        if (entries.count() < 2 || entries.first().endsWith(head))
            continue;
        const QString ref = entries.at(0).mid(remotesPrefix.size());
        int refBranchIndex = ref.indexOf(QLatin1Char('/'));
        int timeT = entries.at(1).left(entries.at(1).indexOf(QLatin1Char(' '))).toInt();
        BranchDate bd(ref.mid(refBranchIndex + 1), QDateTime::fromTime_t(timeT).date());
        m_remoteBranches.insertMulti(ref.left(refBranchIndex), bd);
    }

    int currIndex = 0;
    QStringList remotes = m_remoteBranches.keys();
    remotes.removeDuplicates();
    foreach (const QString &remote, remotes) {
        m_ui->remoteComboBox->addItem(remote);
        if (remote == m_suggestedRemoteName)
            m_ui->remoteComboBox->setCurrentIndex(currIndex);
        ++currIndex;
    }
    const int remoteCount = m_ui->remoteComboBox->count();
    if (remoteCount < 1) {
        return;
    } else if (remoteCount == 1) {
        m_ui->remoteLabel->hide();
        m_ui->remoteComboBox->hide();
    } else {
        connect(m_ui->remoteComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setRemoteBranches()));
    }
    connect(m_ui->branchComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setChangeRange()));
    setRemoteBranches();
    m_ui->reviewersLineEdit->setText(reviewerList);

    m_ui->topicLineEdit->setValidator(new QRegExpValidator(QRegExp(QLatin1String("^\\S+$")), this));

    m_valid = true;
}

GerritPushDialog::~GerritPushDialog()
{
    delete m_ui;
}

QString GerritPushDialog::selectedCommit() const
{
    return m_ui->commitView->commit();
}

QString GerritPushDialog::calculateChangeRange()
{
    QString remote = selectedRemoteName();
    remote += QLatin1Char('/');
    remote += selectedRemoteBranchName();

    QStringList args(remote + QLatin1String("..HEAD"));
    args << QLatin1String("--count");

    QString number;

    if (!Git::Internal::GitPlugin::instance()->gitClient()->
            synchronousRevListCmd(m_workingDir, args, &number))
        reject();

    number.chop(1);
    return number;
}

void GerritPushDialog::setChangeRange()
{
    if (m_ui->branchComboBox->itemData(m_ui->branchComboBox->currentIndex()) == 1) {
        setRemoteBranches(true);
        return;
    }
    QString remote = selectedRemoteName();
    remote += QLatin1Char('/');
    remote += selectedRemoteBranchName();
    m_ui->infoLabel->setText(tr("Number of commits between HEAD and %1: %2").arg(
                                 remote, calculateChangeRange()));
}

bool GerritPushDialog::localChangesFound() const
{
    return m_localChangesFound;
}

bool GerritPushDialog::valid() const
{
    return m_valid;
}

void GerritPushDialog::setRemoteBranches(bool includeOld)
{
    bool blocked = m_ui->branchComboBox->blockSignals(true);
    m_ui->branchComboBox->clear();

    int i = 0;
    bool excluded = false;
    for (RemoteBranchesMap::const_iterator it = m_remoteBranches.constBegin(),
         end = m_remoteBranches.constEnd();
         it != end; ++it) {
        if (it.key() == selectedRemoteName()) {
            const BranchDate &bd = it.value();
            const bool isSuggested = bd.first == m_suggestedRemoteBranch;
            if (includeOld || bd.second.daysTo(QDate::currentDate()) <= 60 || isSuggested) {
                m_ui->branchComboBox->addItem(bd.first);
                if (isSuggested)
                    m_ui->branchComboBox->setCurrentIndex(i);
                ++i;
            } else {
                excluded = true;
            }
        }
    }
    if (excluded)
        m_ui->branchComboBox->addItem(tr("... Include older branches ..."), 1);
    setChangeRange();
    m_ui->branchComboBox->blockSignals(blocked);
}

QString GerritPushDialog::selectedRemoteName() const
{
    return m_ui->remoteComboBox->currentText();
}

QString GerritPushDialog::selectedRemoteBranchName() const
{
    return m_ui->branchComboBox->currentText();
}

QString GerritPushDialog::selectedPushType() const
{
    return m_ui->draftCheckBox->isChecked() ? QLatin1String("draft") : QLatin1String("for");
}

QString GerritPushDialog::selectedTopic() const
{
    return m_ui->topicLineEdit->text().trimmed();
}

QString GerritPushDialog::reviewers() const
{
    return m_ui->reviewersLineEdit->text();
}

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


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. 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.
 * 3. Neither the name PX4 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.
 *
 ****************************************************************************/

/**
 * @file gpio_test.cpp
 * @author Julian Kent <julian@auterion.com>
 *
 * GPIO read and write tool
 */

#include <px4_platform_common/log.h>
#include <px4_platform_common/module.h>
#include <px4_platform_common/px4_config.h>

__BEGIN_DECLS
__EXPORT int gpio_main(int argc, char *argv[]);
__END_DECLS

static void
usage(const char *reason)
{
	printf("FAIL\n");

	if (reason != nullptr) {
		PX4_WARN("%s", reason);
	}

	PRINT_MODULE_DESCRIPTION(
		R"DESCR_STR(
### Description
This command is used to read and write GPIOs

gpio read <PORT> <PIN> [PULLDOWN|PULLUP] [--force]
gpio write <PORT> <PIN> <VALUE> [PUSHPULL|OPENDRAIN] [--force]

### Examples
Read the value on port H pin 4 configured as pullup, and it is high
$ gpio_test read H 4 PU
1 OK

Set the output value on Port E pin 7 to high
$ gpio_test write E 7 1 --force
OK

)DESCR_STR");

}

int
gpio_main(int argc, char *argv[])
{
	if (argc < 4) {
		usage("not enough arguments");
		return -1;
	}

	const char* command = argv[1];
	bool is_read = false;
	uint32_t mask = 0;
	if (strcmp(command, "read") == 0) {
		is_read = true;
		mask |= GPIO_INPUT;
	} else if (strcmp(command, "write") == 0) {
		if (argc < 5) {
			usage("not enough arguments");
			return -1;
		}
		mask |= GPIO_OUTPUT;
	} else {
		usage("command not read or write");
		return -1;
	}

	const char* port_string = argv[2];
	if (strlen(port_string) != 1) {
		usage("port not a single character");
	}
	char port = port_string[0];
	if ('A' <= port && port <= 'K') {
		mask |= ((port - 'A') << GPIO_PORT_SHIFT) & GPIO_PORT_MASK;
	} else if ('a' <= port && port <= 'k') {
		mask |= ((port - 'a') << GPIO_PORT_SHIFT) & GPIO_PORT_MASK;
	} else {
		usage("invalid port");
		return -1;
	}

	char *end;
	int32_t pin = strtol(argv[3], &end, 10);
	if (errno == 0 && *end == '\0' && 0 <= pin && pin <= 15) {
		mask |= (pin << GPIO_PIN_SHIFT) & GPIO_PIN_MASK;;
	} else {
		usage("invalid pin");
		return -1;
	}

	bool matches_default_config = false;
#ifdef PX4_GPIO_INIT_LIST
	const uint32_t default_gpios[] = PX4_GPIO_INIT_LIST;
	// check that GPIO matches initialization list for port/pin and input/output
	for (uint32_t i = 0; i < arraySize(default_gpios); i++) {
		if ((((default_gpios[i] & GPIO_INPUT) == (mask & GPIO_INPUT)) ||
		    ((default_gpios[i] & GPIO_OUTPUT) == (mask & GPIO_OUTPUT)))
		    && ((default_gpios[i] & GPIO_PORT_MASK) == (mask & GPIO_PORT_MASK))
		    && ((default_gpios[i] & GPIO_PIN_MASK) == (mask & GPIO_PIN_MASK))
		) {
			matches_default_config = true;
		}
	}
#endif
	bool force_apply = strcasecmp(argv[argc-1], "--force") == 0;

	if (!matches_default_config && !force_apply) {
		usage ("does not match board initialization list, and --force not specified");
		return -1;
	}

	if (is_read) {
		if (argc >= 5) {
			const char* extra = argv[4];
			if (strcasecmp(extra, "PULLUP") == 0) {
				mask |= GPIO_PULLUP;
			} else if (strcasecmp(extra, "PULLDOWN") == 0) {
				mask |= GPIO_PULLDOWN;
			} else if (argc == 5 && !force_apply) {
				usage ("extra read argument not PULLUP or PULLDOWN");
				return -1;
			}
		}

		px4_arch_configgpio(mask);
		int value = px4_arch_gpioread(mask);
		printf("%d OK\n", value);
	} else {
		int32_t value = strtol(argv[4], &end, 10);
		if (errno != 0 || *end != '\0' || (value != 0 && value != 1)) {
			usage("value not 0 or 1");
			return -1;
		}

		if (argc >= 6) {
			const char* extra = argv[5];
			if (strcasecmp(extra, "PUSHPULL") == 0) {
				mask |= GPIO_PUSHPULL;
			} else if (strcasecmp(extra, "OPENDRAIN") == 0) {
				mask |= GPIO_OPENDRAIN;
			} else if (argc == 6 && !force_apply) {
				usage("extra write argument not PUSHPULL or OPENDRAIN");
				return -1;
			}
		}

		px4_arch_configgpio(mask);
		px4_arch_gpiowrite(mask, value);
		printf("OK\n");
	}
	return 0;
}
<commit_msg>systemcmds/gpio: move usage description to bottom and fix formatting<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. 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.
 * 3. Neither the name PX4 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.
 *
 ****************************************************************************/

/**
 * @file gpio_test.cpp
 * @author Julian Kent <julian@auterion.com>
 *
 * GPIO read and write tool
 */

#include <px4_platform_common/log.h>
#include <px4_platform_common/module.h>
#include <px4_platform_common/px4_config.h>

static void usage(const char *reason);

extern "C" __EXPORT int gpio_main(int argc, char *argv[])
{
	if (argc < 4) {
		usage("not enough arguments");
		return -1;
	}

	const char *command = argv[1];
	bool is_read = false;
	uint32_t mask = 0;

	if (strcmp(command, "read") == 0) {
		is_read = true;
		mask |= GPIO_INPUT;

	} else if (strcmp(command, "write") == 0) {
		if (argc < 5) {
			usage("not enough arguments");
			return -1;
		}

		mask |= GPIO_OUTPUT;

	} else {
		usage("command not read or write");
		return -1;
	}

	const char *port_string = argv[2];

	if (strlen(port_string) != 1) {
		usage("port not a single character");
	}

	char port = port_string[0];

	if ('A' <= port && port <= 'K') {
		mask |= ((port - 'A') << GPIO_PORT_SHIFT) & GPIO_PORT_MASK;

	} else if ('a' <= port && port <= 'k') {
		mask |= ((port - 'a') << GPIO_PORT_SHIFT) & GPIO_PORT_MASK;

	} else {
		usage("invalid port");
		return -1;
	}

	char *end;
	int32_t pin = strtol(argv[3], &end, 10);

	if (errno == 0 && *end == '\0' && 0 <= pin && pin <= 15) {
		mask |= (pin << GPIO_PIN_SHIFT) & GPIO_PIN_MASK;;

	} else {
		usage("invalid pin");
		return -1;
	}

	bool matches_default_config = false;
#if defined(PX4_GPIO_INIT_LIST)
	const uint32_t default_gpios[] = PX4_GPIO_INIT_LIST;

	// check that GPIO matches initialization list for port/pin and input/output
	for (uint32_t i = 0; i < arraySize(default_gpios); i++) {
		if ((((default_gpios[i] & GPIO_INPUT) == (mask & GPIO_INPUT)) ||
		     ((default_gpios[i] & GPIO_OUTPUT) == (mask & GPIO_OUTPUT)))
		    && ((default_gpios[i] & GPIO_PORT_MASK) == (mask & GPIO_PORT_MASK))
		    && ((default_gpios[i] & GPIO_PIN_MASK) == (mask & GPIO_PIN_MASK))
		   ) {
			matches_default_config = true;
		}
	}

#endif // PX4_GPIO_INIT_LIST
	bool force_apply = strcasecmp(argv[argc - 1], "--force") == 0;

	if (!matches_default_config && !force_apply) {
		usage("does not match board initialization list, and --force not specified");
		return -1;
	}

	if (is_read) {
		if (argc >= 5) {
			const char *extra = argv[4];

			if (strcasecmp(extra, "PULLUP") == 0) {
				mask |= GPIO_PULLUP;

			} else if (strcasecmp(extra, "PULLDOWN") == 0) {
				mask |= GPIO_PULLDOWN;

			} else if (argc == 5 && !force_apply) {
				usage("extra read argument not PULLUP or PULLDOWN");
				return -1;
			}
		}

		px4_arch_configgpio(mask);
		int value = px4_arch_gpioread(mask);
		printf("%d OK\n", value);

	} else {
		int32_t value = strtol(argv[4], &end, 10);

		if (errno != 0 || *end != '\0' || (value != 0 && value != 1)) {
			usage("value not 0 or 1");
			return -1;
		}

		if (argc >= 6) {
			const char *extra = argv[5];

			if (strcasecmp(extra, "PUSHPULL") == 0) {
				mask |= GPIO_PUSHPULL;

			} else if (strcasecmp(extra, "OPENDRAIN") == 0) {
				mask |= GPIO_OPENDRAIN;

			} else if (argc == 6 && !force_apply) {
				usage("extra write argument not PUSHPULL or OPENDRAIN");
				return -1;
			}
		}

		px4_arch_configgpio(mask);
		px4_arch_gpiowrite(mask, value);
		printf("OK\n");
	}

	return 0;
}

void usage(const char *reason)
{
	printf("FAIL\n");

	if (reason != nullptr) {
		PX4_WARN("%s", reason);
	}

	PRINT_MODULE_DESCRIPTION(
		R"DESCR_STR(
### Description
This command is used to read and write GPIOs

gpio read <PORT> <PIN> [PULLDOWN|PULLUP] [--force]
gpio write <PORT> <PIN> <VALUE> [PUSHPULL|OPENDRAIN] [--force]

### Examples
Read the value on port H pin 4 configured as pullup, and it is high
$ gpio_test read H 4 PU
1 OK

Set the output value on Port E pin 7 to high
$ gpio_test write E 7 1 --force
OK

)DESCR_STR");

}
<|endoftext|>


<commit_before>/*
* tcpServer.cpp
* version 180418rev4
* Created at 2017/06/25
* Copyright (C) 2017 zhai <holmesfems@gmail.com>
*
* Distributed under terms of the MIT license.
*/
#include "tcpServer.h"
#include <sstream>

namespace TcpServer
{
	const std::string TcpServer::EXIT_MSG("EXIT SERVER");
	const std::string TcpServer::LOST_MSG("LOST CONNECTION");

	TcpServer::TcpServer(boost::asio::io_service &io_service, uint16_t port, std::ostream *os)
		: _io(io_service),
		_socket(io_service),
		_os(os),
		_port(port),
		_acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
	{
		if (_os == NULL) //dummy
			_os = new std::ostringstream();
		_writeDone = true;
	}

	void TcpServer::start_accept()
	{
		_connection_status = _connection_status_writer.get_future().share();
		_acceptor.async_accept(
			_socket,
			boost::bind(&TcpServer::_on_accept, this, boost::asio::placeholders::error));
	}

	void TcpServer::send(std::string msg)
	{
		_msgQueue.push(msg);
		_refresh_recvMsg();
		if (_writeDone)
			_io.post(boost::bind(&TcpServer::_async_write, this));
	}

	bool TcpServer::is_connected(int timeout)
	{
		try
		{
			if (timeout < 0 || _connection_status.wait_for(std::chrono::milliseconds(timeout)) == std::future_status::ready)
			{
				return (_connection_status.get()) == ONLINE;
			}
			else
			{
				return false;
			}
		}
		catch (std::future_error e)
		{
			return status == ONLINE;
		}
	}

	bool TcpServer::is_online(int timeout)
	{
		if (is_connected(timeout))
		{
			return status == ONLINE;
		}
		else
		{
			return false;
		}
	}

	std::string TcpServer::lastRecv(int timeout)
	{
		_refresh_doneFlag();
		std::string ret;
		if (timeout < 0 || _receive_msg.wait_for(std::chrono::milliseconds(timeout)) == std::future_status::ready)
		{
			try
			{
				ret = _receive_msg.get();
			}
			catch (std::future_error e)
			{
				std::ostringstream oss;
				oss << "Future Error:" << e.what();
				ret = oss.str();
			}
		}
		else
		{
			ret = "MSG NOT VALID (Timeout)";
		}
		_done();
		return ret;
	}

	std::string TcpServer::waitRecv()
	{
		_refresh_doneFlag();
		_clear_recvMsg();
		std::string ret;
		try
		{
			ret = _receive_msg.get();
		}
		catch (std::future_error e)
		{
			std::ostringstream oss;
			oss << "Future error:" << e.what();
			ret = oss.str();
		}
		_done();
		return ret;
	}

	bool TcpServer::waitAllDone(int timeout)
	{
		if (!_doneFlag.valid())
		{
			return true;
		}
		if (timeout < 0 || _doneFlag.wait_for(std::chrono::milliseconds(timeout)) == std::future_status::ready)
		{
			try
			{
				bool ret = _doneFlag.get();
			}
			catch (std::future_error e)
			{
				std::ostringstream oss;
				oss << "Future Error:" << e.what();
				return false;
			}
		}
		else
		{
			return false;
		}
	}

	void TcpServer::exit()
	{
		try
		{
			status = EXIT;
			_connection_status_writer.set_value(status);
		}
		catch (std::future_error e)
		{
			if (e.code() != std::future_errc::promise_already_satisfied)
			{
				*_os << "Future error:";
				*_os << e.what();
			}
		}
		try
		{
			_receive_msg_writer.set_value(EXIT_MSG);
		}
		catch (std::future_error e)
		{
			if (e.code() != std::future_errc::promise_already_satisfied)
			{
				*_os << "Future error:";
				*_os << e.what();
			}
		}
		waitAllDone();
		_io.stop();
	}

	void TcpServer::_on_accept(const boost::system::error_code &err)
	{
		if (err)
		{
			*_os << "Failed to accept : " << err.message() << std::endl;
			status = FAIL;
			_connection_status_writer.set_value(status);
		}
		else
		{
			*_os << "Connection accepted" << std::endl;
			status = ONLINE;
			_connection_status_writer.set_value(status);
			_async_receive();
		}
	}

	void TcpServer::_async_receive()
	{
		boost::asio::async_read_until(
			_socket,
			_receive_buff,
			"\n",
			boost::bind(&TcpServer::_on_receive, this,
				boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
	}

	void TcpServer::_on_receive(const boost::system::error_code &err, size_t bytes_transferred)
	{
		//std::cout << "now status = " << status << std::endl;
		//std::cout.flush();
		if (status == EXIT) return;
		if (err && err != boost::asio::error::eof) {
			*_os << "receive failed: " << err.message() << std::endl;
			status = FAIL;
			//start_accept();
		}
		else {

			std::string data = std::string(boost::asio::buffer_cast<const char*>(_receive_buff.data()), bytes_transferred);
			data = data.substr(0, data.length() - 1);

			if (bytes_transferred == 0 && err == boost::asio::error::eof)
			{
				*_os << "connection lost!" << std::endl;
				if (status != EXIT)
				{
					status = LOST;
					//start_accept();
				}

				try
				{
					_receive_msg_writer.set_value(LOST_MSG);
				}
				catch (std::future_error e)
				{
					if (e.code() != std::future_errc::promise_already_satisfied)
					{
						*_os << "Future error:";
						*_os << e.what();
					}
				}

//				_on_offline();
			}
			else
			{
				*_os << "recieve succeed " << "length = " << bytes_transferred << std::endl;
				*_os << "cmd = \"" << data << "\"" << std::endl;
				try
				{
					_receive_msg_writer.set_value(data);
				}
				catch (std::future_error e)
				{
					if (e.code() != std::future_errc::promise_already_satisfied)
					{
						*_os << "Promise error occured:" << e.what() << std::endl;
					}
					else
					{
						*_os << "Already satisfied!" << std::endl;
					}
				}
				if (!(data == "exit"))
				{
					_receive_buff.consume(_receive_buff.size());
					_async_receive();
				}
				else
				{
					status = EXIT;
				}
			}
		}
	}

	void TcpServer::_async_write()
	{
		if (_msgQueue.empty())
		{
			_writeDone = true;
			return;
		}
		_writeDone = false;
		std::string msg = _msgQueue.front();
		_msgQueue.pop();
		msg = msg + "\n";
		boost::asio::async_write(
			_socket,
			boost::asio::buffer(msg.c_str(), msg.length()),
			boost::bind(&TcpServer::_on_write, this,
				boost::asio::placeholders::error));
	}

	void TcpServer::_on_write(const boost::system::error_code & err)
	{
		if (err)
		{
			*_os << "write failed" << std::endl;
		}
		else
		{
			*_os << "write succeed" << std::endl;
			if (!_msgQueue.empty())
				_async_write();
			else
				_writeDone = true;
		}
	}

	void TcpServer::_refresh_doneFlag()
	{
		std::promise<bool> newpromise;
		_doneFlag_writer.swap(newpromise);
		_doneFlag = _doneFlag_writer.get_future().share();
	}

	void TcpServer::_done()
	{
		try
		{
			_doneFlag_writer.set_value(true);
		}
		catch (std::future_error e)
		{
			if (e.code() != std::future_errc::promise_already_satisfied)
			{
				*_os << "Promise error occured: " << e.what() << std::endl;
			}
		}
	}

	void TcpServer::_clear_recvMsg()
	{
		std::promise<std::string> newpromise;
		_receive_msg_writer.swap(newpromise);
		_receive_msg = _receive_msg_writer.get_future();
	}

	void TcpServer::_refresh_recvMsg()
	{
		if (!_receive_msg.valid() || _receive_msg.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready)
		{
			_clear_recvMsg();
		}
	}
}<commit_msg>fixing code bug<commit_after>/*
* tcpServer.cpp
* version 180418rev4
* Created at 2017/06/25
* Copyright (C) 2017 zhai <holmesfems@gmail.com>
*
* Distributed under terms of the MIT license.
*/
#include "tcpServer.h"
#include <sstream>

namespace TcpServer
{
	const std::string TcpServer::EXIT_MSG("EXIT SERVER");
	const std::string TcpServer::LOST_MSG("LOST CONNECTION");

	TcpServer::TcpServer(boost::asio::io_service &io_service, uint16_t port, std::ostream *os)
		: _io(io_service),
		_socket(io_service),
		_os(os),
		_port(port),
		_acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
	{
		if (_os == NULL) //dummy
			_os = new std::ostringstream();
		_writeDone = true;
	}

	void TcpServer::start_accept()
	{
		_connection_status = _connection_status_writer.get_future().share();
		_acceptor.async_accept(
			_socket,
			boost::bind(&TcpServer::_on_accept, this, boost::asio::placeholders::error));
	}

	void TcpServer::send(std::string msg)
	{
		_msgQueue.push(msg);
		_refresh_recvMsg();
		if (_writeDone)
			_io.post(boost::bind(&TcpServer::_async_write, this));
	}

	bool TcpServer::is_connected(int timeout)
	{
		try
		{
			if (timeout < 0 || _connection_status.wait_for(std::chrono::milliseconds(timeout)) == std::future_status::ready)
			{
				return (_connection_status.get()) == ONLINE;
			}
			else
			{
				return false;
			}
		}
		catch (std::future_error e)
		{
			return status == ONLINE;
		}
	}

	bool TcpServer::is_online(int timeout)
	{
		if (is_connected(timeout))
		{
			return status == ONLINE;
		}
		else
		{
			return false;
		}
	}

	std::string TcpServer::lastRecv(int timeout)
	{
		_refresh_doneFlag();
		std::string ret;
		if (timeout < 0 || _receive_msg.wait_for(std::chrono::milliseconds(timeout)) == std::future_status::ready)
		{
			try
			{
				ret = _receive_msg.get();
			}
			catch (std::future_error e)
			{
				std::ostringstream oss;
				oss << "Future Error:" << e.what();
				ret = oss.str();
			}
		}
		else
		{
			ret = "MSG NOT VALID (Timeout)";
		}
		_done();
		return ret;
	}

	std::string TcpServer::waitRecv()
	{
		_refresh_doneFlag();
		_clear_recvMsg();
		std::string ret;
		try
		{
			ret = _receive_msg.get();
		}
		catch (std::future_error e)
		{
			std::ostringstream oss;
			oss << "Future error:" << e.what();
			ret = oss.str();
		}
		_done();
		return ret;
	}

	bool TcpServer::waitAllDone(int timeout)
	{
		if (!_doneFlag.valid())
		{
			return true;
		}
		if (timeout < 0 || _doneFlag.wait_for(std::chrono::milliseconds(timeout)) == std::future_status::ready)
		{
			try
			{
				return _doneFlag.get();
			}
			catch (std::future_error e)
			{
				std::ostringstream oss;
				oss << "Future Error:" << e.what();
				return false;
			}
		}
		else
		{
			return false;
		}
	}

	void TcpServer::exit()
	{
		try
		{
			status = EXIT;
			_connection_status_writer.set_value(status);
		}
		catch (std::future_error e)
		{
			if (e.code() != std::future_errc::promise_already_satisfied)
			{
				*_os << "Future error:";
				*_os << e.what();
			}
		}
		try
		{
			_receive_msg_writer.set_value(EXIT_MSG);
		}
		catch (std::future_error e)
		{
			if (e.code() != std::future_errc::promise_already_satisfied)
			{
				*_os << "Future error:";
				*_os << e.what();
			}
		}
		waitAllDone();
		_io.stop();
	}

	void TcpServer::_on_accept(const boost::system::error_code &err)
	{
		if (err)
		{
			*_os << "Failed to accept : " << err.message() << std::endl;
			status = FAIL;
			_connection_status_writer.set_value(status);
		}
		else
		{
			*_os << "Connection accepted" << std::endl;
			status = ONLINE;
			_connection_status_writer.set_value(status);
			_async_receive();
		}
	}

	void TcpServer::_async_receive()
	{
		boost::asio::async_read_until(
			_socket,
			_receive_buff,
			"\n",
			boost::bind(&TcpServer::_on_receive, this,
				boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
	}

	void TcpServer::_on_receive(const boost::system::error_code &err, size_t bytes_transferred)
	{
		//std::cout << "now status = " << status << std::endl;
		//std::cout.flush();
		if (status == EXIT) return;
		if (err && err != boost::asio::error::eof) {
			*_os << "receive failed: " << err.message() << std::endl;
			status = FAIL;
			//start_accept();
		}
		else {

			std::string data = std::string(boost::asio::buffer_cast<const char*>(_receive_buff.data()), bytes_transferred);
			data = data.substr(0, data.length() - 1);

			if (bytes_transferred == 0 && err == boost::asio::error::eof)
			{
				*_os << "connection lost!" << std::endl;
				if (status != EXIT)
				{
					status = LOST;
					//start_accept();
				}

				try
				{
					_receive_msg_writer.set_value(LOST_MSG);
				}
				catch (std::future_error e)
				{
					if (e.code() != std::future_errc::promise_already_satisfied)
					{
						*_os << "Future error:";
						*_os << e.what();
					}
				}

//				_on_offline();
			}
			else
			{
				*_os << "recieve succeed " << "length = " << bytes_transferred << std::endl;
				*_os << "cmd = \"" << data << "\"" << std::endl;
				try
				{
					_receive_msg_writer.set_value(data);
				}
				catch (std::future_error e)
				{
					if (e.code() != std::future_errc::promise_already_satisfied)
					{
						*_os << "Promise error occured:" << e.what() << std::endl;
					}
					else
					{
						*_os << "Already satisfied!" << std::endl;
					}
				}
				if (!(data == "exit"))
				{
					_receive_buff.consume(_receive_buff.size());
					_async_receive();
				}
				else
				{
					status = EXIT;
				}
			}
		}
	}

	void TcpServer::_async_write()
	{
		if (_msgQueue.empty())
		{
			_writeDone = true;
			return;
		}
		_writeDone = false;
		std::string msg = _msgQueue.front();
		_msgQueue.pop();
		msg = msg + "\n";
		boost::asio::async_write(
			_socket,
			boost::asio::buffer(msg.c_str(), msg.length()),
			boost::bind(&TcpServer::_on_write, this,
				boost::asio::placeholders::error));
	}

	void TcpServer::_on_write(const boost::system::error_code & err)
	{
		if (err)
		{
			*_os << "write failed" << std::endl;
		}
		else
		{
			*_os << "write succeed" << std::endl;
			if (!_msgQueue.empty())
				_async_write();
			else
				_writeDone = true;
		}
	}

	void TcpServer::_refresh_doneFlag()
	{
		std::promise<bool> newpromise;
		_doneFlag_writer.swap(newpromise);
		_doneFlag = _doneFlag_writer.get_future().share();
	}

	void TcpServer::_done()
	{
		try
		{
			_doneFlag_writer.set_value(true);
		}
		catch (std::future_error e)
		{
			if (e.code() != std::future_errc::promise_already_satisfied)
			{
				*_os << "Promise error occured: " << e.what() << std::endl;
			}
		}
	}

	void TcpServer::_clear_recvMsg()
	{
		std::promise<std::string> newpromise;
		_receive_msg_writer.swap(newpromise);
		_receive_msg = _receive_msg_writer.get_future();
	}

	void TcpServer::_refresh_recvMsg()
	{
		if (!_receive_msg.valid() || _receive_msg.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready)
		{
			_clear_recvMsg();
		}
	}
}<|endoftext|>