<commit_before>/*
 * This file is part of the Electron Orbital Explorer. The Electron
 * Orbital Explorer is distributed under the Simplified BSD License
 * (also called the "BSD 2-Clause License"), in hopes that these
 * rendering techniques might be used by other programmers in
 * applications such as scientific visualization, video gaming, and so
 * on. If you find value in this software and use its technologies for
 * another purpose, I would love to hear back from you at bjthinks (at)
 * gmail (dot) com. If you improve this software and agree to release
 * your modifications under the below license, I encourage you to fork
 * the development tree on github and push your modifications. The
 * Electron Orbital Explorer's development URL is:
 * https://github.com/bjthinks/orbital-explorer
 * (This paragraph is not part of the software license and may be
 * removed.)
 *
 * Copyright (c) 2013, Brian W. Johnson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * + Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * + Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 *
 * 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 HOLDER 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.
 */

/*
 * This file is a derivative work of Philippe Decaudin's AntTweakBar
 * library, version 1.16, which is distributed under the following terms:
 *
 * Copyright (C) 2005-2013 Philippe Decaudin
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must
 * not claim that you wrote the original software. If you use this
 * software in a product, an acknowledgment in the product documentation
 * would be appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and must
 * not be misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source
 * distribution.
 */

#include <AntTweakBar.h>

#include "SDLtoATB.hh"

// TwEventSDL returns zero if msg has not been handled,
// and a non-zero value if it has been handled by the AntTweakBar library.
int TW_CALL myTwEventSDL20(const SDL_Event &event)
{
  int handled = 0;
  //static int s_KeyMod = 0;

  switch (event.type) {

#if 0
  case SDL_TEXTINPUT:
    if (event.text.text[0] != 0 && event.text.text[1] == 0) {
      if (s_KeyMod & TW_KMOD_CTRL && event.text.text[0] < 32)
        handled = TwKeyPressed(event.text.text[0] + 'a' - 1, s_KeyMod);
      else {
        if (s_KeyMod & KMOD_RALT)
          s_KeyMod &= ~KMOD_CTRL;
        handled = TwKeyPressed(event.text.text[0], s_KeyMod);
      }
    }
    s_KeyMod = 0;
    break;

  case SDL_KEYDOWN:
    if (event.key.keysym.sym & SDLK_SCANCODE_MASK) {
      int key = 0;
      switch (event.key.keysym.sym) {
      case SDLK_UP:
        key = TW_KEY_UP;
        break;
      case SDLK_DOWN:
        key = TW_KEY_DOWN;
        break;
      case SDLK_RIGHT:
        key = TW_KEY_RIGHT;
        break;
      case SDLK_LEFT:
        key = TW_KEY_LEFT;
        break;
      case SDLK_INSERT:
        key = TW_KEY_INSERT;
        break;
      case SDLK_HOME:
        key = TW_KEY_HOME;
        break;
      case SDLK_END:
        key = TW_KEY_END;
        break;
      case SDLK_PAGEUP:
        key = TW_KEY_PAGE_UP;
        break;
      case SDLK_PAGEDOWN:
        key = TW_KEY_PAGE_DOWN;
        break;
      default:
        if (event.key.keysym.sym >= SDLK_F1 &&
            event.key.keysym.sym <= SDLK_F12)
          key = event.key.keysym.sym + TW_KEY_F1 - SDLK_F1;
      }
      if (key != 0)
        handled = TwKeyPressed(key, event.key.keysym.mod);
    }
    else if (event.key.keysym.mod & TW_KMOD_ALT)
      handled = TwKeyPressed(event.key.keysym.sym & 0xFF,
                             event.key.keysym.mod);
    else
      s_KeyMod = event.key.keysym.mod;
    break;

  case SDL_KEYUP:
    s_KeyMod = 0;
    break;
#endif

  case SDL_MOUSEMOTION:
    handled = TwMouseMotion(event.motion.x, event.motion.y);
    break;

  case SDL_MOUSEWHEEL:
    {
      static int s_WheelPos = 0;
      s_WheelPos += event.wheel.y;
      handled = TwMouseWheel(s_WheelPos);
    }
    break;

  case SDL_MOUSEBUTTONUP:
  case SDL_MOUSEBUTTONDOWN:
    TwMouseAction action;
    if (event.button.state == SDL_PRESSED)
      action = TW_MOUSE_PRESSED;
    else if (event.button.state == SDL_RELEASED)
      action = TW_MOUSE_RELEASED;
    else
      break;

    TwMouseButtonID button;
    if (event.button.button == SDL_BUTTON_LMASK)
      button = TW_MOUSE_LEFT;
    else if (event.button.button == SDL_BUTTON_MMASK)
      button = TW_MOUSE_MIDDLE;
    else if (event.button.button == SDL_BUTTON_RMASK)
      button = TW_MOUSE_RIGHT;
    else
      break;

    handled = TwMouseButton(action, button);

    break;

  case SDL_WINDOWEVENT:
    if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
      // tell the new size to TweakBar
      TwWindowSize(event.window.data1, event.window.data2);
      // do not set 'handled', SDL_VIDEORESIZE may be also processed by
      // the calling application
    }
    break;
  }

  return handled;
}
<commit_msg>Handle ATB keyboard events properly. It's not clear if the modified AntTweakBar code is entirely correct, but it appears to be good enough for our purposes.<commit_after>/*
 * This file is part of the Electron Orbital Explorer. The Electron
 * Orbital Explorer is distributed under the Simplified BSD License
 * (also called the "BSD 2-Clause License"), in hopes that these
 * rendering techniques might be used by other programmers in
 * applications such as scientific visualization, video gaming, and so
 * on. If you find value in this software and use its technologies for
 * another purpose, I would love to hear back from you at bjthinks (at)
 * gmail (dot) com. If you improve this software and agree to release
 * your modifications under the below license, I encourage you to fork
 * the development tree on github and push your modifications. The
 * Electron Orbital Explorer's development URL is:
 * https://github.com/bjthinks/orbital-explorer
 * (This paragraph is not part of the software license and may be
 * removed.)
 *
 * Copyright (c) 2013, Brian W. Johnson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * + Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * + Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 *
 * 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 HOLDER 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.
 */

/*
 * This file is a derivative work of Philippe Decaudin's AntTweakBar
 * library, version 1.16, which is distributed under the following terms:
 *
 * Copyright (C) 2005-2013 Philippe Decaudin
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must
 * not claim that you wrote the original software. If you use this
 * software in a product, an acknowledgment in the product documentation
 * would be appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and must
 * not be misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source
 * distribution.
 */

#include <AntTweakBar.h>

#include "SDLtoATB.hh"

// TwEventSDL returns zero if msg has not been handled,
// and a non-zero value if it has been handled by the AntTweakBar library.
int TW_CALL myTwEventSDL20(const SDL_Event &event)
{
  int handled = 0;
  static int s_KeyMod = 0;

  switch (event.type) {

  case SDL_TEXTINPUT:
    if (event.text.text[0] != 0 && event.text.text[1] == 0) {
      if (s_KeyMod & TW_KMOD_CTRL && event.text.text[0] < 32)
        handled = TwKeyPressed(event.text.text[0] + 'a' - 1, s_KeyMod);
      else {
        if (s_KeyMod & KMOD_RALT)
          s_KeyMod &= ~KMOD_CTRL;
        handled = TwKeyPressed(event.text.text[0], s_KeyMod);
      }
    }
    break;

  case SDL_KEYDOWN:
    if (event.key.keysym.sym & SDLK_SCANCODE_MASK) {
      int key = 0;
      switch (event.key.keysym.sym) {
      case SDLK_UP:
        key = TW_KEY_UP;
        break;
      case SDLK_DOWN:
        key = TW_KEY_DOWN;
        break;
      case SDLK_RIGHT:
        key = TW_KEY_RIGHT;
        break;
      case SDLK_LEFT:
        key = TW_KEY_LEFT;
        break;
      case SDLK_INSERT:
        key = TW_KEY_INSERT;
        break;
      case SDLK_HOME:
        key = TW_KEY_HOME;
        break;
      case SDLK_END:
        key = TW_KEY_END;
        break;
      case SDLK_PAGEUP:
        key = TW_KEY_PAGE_UP;
        break;
      case SDLK_PAGEDOWN:
        key = TW_KEY_PAGE_DOWN;
        break;
      default:
        if (event.key.keysym.sym >= SDLK_F1 &&
            event.key.keysym.sym <= SDLK_F12)
          key = event.key.keysym.sym + TW_KEY_F1 - SDLK_F1;
      }
      if (key != 0)
        handled = TwKeyPressed(key, event.key.keysym.mod);
    }
    else if (event.key.keysym.mod & TW_KMOD_ALT)
      handled = TwKeyPressed(event.key.keysym.sym & 0xFF,
                             event.key.keysym.mod);
    s_KeyMod = event.key.keysym.mod;
    break;

  case SDL_KEYUP:
    s_KeyMod = event.key.keysym.mod;
    break;

  case SDL_MOUSEMOTION:
    handled = TwMouseMotion(event.motion.x, event.motion.y);
    break;

  case SDL_MOUSEWHEEL:
    {
      static int s_WheelPos = 0;
      s_WheelPos += event.wheel.y;
      handled = TwMouseWheel(s_WheelPos);
    }
    break;

  case SDL_MOUSEBUTTONUP:
  case SDL_MOUSEBUTTONDOWN:
    TwMouseAction action;
    if (event.button.state == SDL_PRESSED)
      action = TW_MOUSE_PRESSED;
    else if (event.button.state == SDL_RELEASED)
      action = TW_MOUSE_RELEASED;
    else
      break;

    TwMouseButtonID button;
    if (event.button.button == SDL_BUTTON_LMASK)
      button = TW_MOUSE_LEFT;
    else if (event.button.button == SDL_BUTTON_MMASK)
      button = TW_MOUSE_MIDDLE;
    else if (event.button.button == SDL_BUTTON_RMASK)
      button = TW_MOUSE_RIGHT;
    else
      break;

    handled = TwMouseButton(action, button);

    break;

  case SDL_WINDOWEVENT:
    if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
      // tell the new size to TweakBar
      TwWindowSize(event.window.data1, event.window.data2);
      // do not set 'handled', SDL_VIDEORESIZE may be also processed by
      // the calling application
    }
    break;
  }

  return handled;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** 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://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, 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 "probe.h"

#include "msvcprobe.h"
#include "xcodeprobe.h"

#include <logging/translator.h>
#include <tools/architectures.h>
#include <tools/error.h>
#include <tools/hostosinfo.h>
#include <tools/profile.h>
#include <tools/scripttools.h>
#include <tools/settings.h>

#include <QDir>
#include <QFileInfo>
#include <QProcess>
#include <QStringList>
#include <QTextStream>

#include <cstdio>

using namespace qbs;
using Internal::HostOsInfo;
using Internal::Tr;

static QTextStream qStdout(stdout);
static QTextStream qStderr(stderr);

static QString findExecutable(const QString &fileName)
{
    const QString path = QString::fromLocal8Bit(qgetenv("PATH"));
    foreach (const QString &ppath, path.split(HostOsInfo::pathListSeparator())) {
        const QString fullPath = ppath + QLatin1Char('/') + fileName;
        if (QFileInfo(fullPath).exists())
            return QDir::cleanPath(fullPath);
    }
    return QString();
}

static QString qsystem(const QString &exe, const QStringList &args = QStringList())
{
    QProcess p;
    p.setProcessChannelMode(QProcess::MergedChannels);
    p.start(exe, args);
    if (!p.waitForStarted()) {
        throw qbs::ErrorInfo(Tr::tr("Failed to start compiler '%1': %2")
                             .arg(exe, p.errorString()));
    }
    if (!p.waitForFinished() || p.exitCode() != 0)
        throw qbs::ErrorInfo(Tr::tr("Failed to run compiler '%1': %2").arg(exe, p.errorString()));
    return QString::fromLocal8Bit(p.readAll());
}

static QStringList validMinGWMachines()
{
    // List of MinGW machine names (gcc -dumpmachine) recognized by Qbs
    return QStringList()
            << QLatin1String("mingw32") << QLatin1String("mingw64")
            << QLatin1String("i686-w64-mingw32") << QLatin1String("x86_64-w64-mingw32")
            << QLatin1String("i586-mingw32msvc") << QLatin1String("amd64-mingw32msvc");
}

static QStringList completeToolchainList(const QString &toolchainName)
{
    QStringList toolchains(toolchainName);
    if (toolchainName == QLatin1String("clang"))
        toolchains << completeToolchainList(QLatin1String("llvm"));
    else if (toolchainName == QLatin1String("llvm") ||
             toolchainName == QLatin1String("mingw")) {
        toolchains << completeToolchainList(QLatin1String("gcc"));
    }
    return toolchains;
}

static QStringList toolchainTypeFromCompilerName(const QString &compilerName)
{
    if (compilerName == QLatin1String("cl.exe"))
        return completeToolchainList(QLatin1String("msvc"));
    foreach (const QString &type, (QStringList() << QLatin1String("clang") << QLatin1String("llvm")
                                                 << QLatin1String("mingw") << QLatin1String("gcc")))
        if (compilerName.contains(type))
            return completeToolchainList(type);
    return QStringList();
}

static QString gccMachineName(const QString &compilerFilePath)
{
    return qsystem(compilerFilePath, QStringList() << QLatin1String("-dumpmachine")).trimmed();
}

static void setupCompilerPathByLanguage(Profile &profile, const QStringList &toolchainTypes,
        const QString &toolchainInstallPath, const QString &toolchainPrefix)
{
    QVariantMap m;
    if (toolchainTypes.contains("clang")) {
        m["c"] = m["objc"] = QLatin1String("clang");
        m["cpp"] = m["objcpp"] = QLatin1String("clang++");
    } else if (toolchainTypes.contains("gcc")) {
        m["c"] = m["objc"] = QLatin1String("gcc");
        m["cpp"] = m["objcpp"] = QLatin1String("g++");
    } else {
        qDebug("WARNING: unexpected toolchain %s", qPrintable(toJSLiteral(toolchainTypes)));
        return;
    }

    const QString toolchainPathPrefix = toolchainInstallPath + QLatin1Char('/') + toolchainPrefix;
    for (QVariantMap::iterator it = m.begin(); it != m.end();) {
        const QString filePath = HostOsInfo::appendExecutableSuffix(toolchainPathPrefix
                                                                    + it.value().toString());
        if (QFile::exists(filePath)) {
            it.value() = filePath;
            ++it;
            continue;
        }
        qDebug("WARNING: Compiler %s for file tag %s not found.",
               qPrintable(QDir::toNativeSeparators(filePath)), qPrintable(it.key()));
        it = m.erase(it);
    }
    if (!m.isEmpty())
        profile.setValue(QLatin1String("cpp.compilerPathByLanguage"), m);
}

static void setCommonProperties(Profile &profile, const QString &compilerFilePath,
        const QString &toolchainPrefix, const QStringList &toolchainTypes,
        const QString &architecture)
{
    QFileInfo cfi(compilerFilePath);
    const QString toolchainInstallPath = cfi.absolutePath();
    profile.setValue(QLatin1String("cpp.toolchainInstallPath"), toolchainInstallPath);
    profile.setValue(QLatin1String("cpp.compilerName"), cfi.fileName());
    profile.setValue(QLatin1String("qbs.toolchain"), toolchainTypes);
    profile.setValue(QLatin1String("qbs.architecture"), canonicalArchitecture(architecture));
    profile.setValue(QLatin1String("qbs.endianness"), defaultEndianness(architecture));
    setupCompilerPathByLanguage(profile, toolchainTypes, toolchainInstallPath, toolchainPrefix);
}

class ToolPathSetup
{
public:
    ToolPathSetup(Profile *profile, const QString &path, const QString &toolchainPrefix)
        : m_profile(profile), m_compilerDirPath(path), m_toolchainPrefix(toolchainPrefix)
    {
    }

    void apply(const QString &toolName, const QString &propertyName) const
    {
        QString toolFileName = m_toolchainPrefix + HostOsInfo::appendExecutableSuffix(toolName);
        if (QFile::exists(m_compilerDirPath + QLatin1Char('/') + toolFileName))
            return;
        const QString toolFilePath = findExecutable(toolFileName);
        if (toolFilePath.isEmpty()) {
            qWarning("%s", qPrintable(
                         QString(QLatin1String("'%1' exists neither in '%2' nor in PATH."))
                            .arg(toolFileName, m_compilerDirPath)));
        }
        m_profile->setValue(propertyName, toolFilePath);
    }

private:
    Profile * const m_profile;
    const QString &m_compilerDirPath;
    const QString &m_toolchainPrefix;
};

static Profile createGccProfile(const QString &compilerFilePath, Settings *settings,
                                const QStringList &toolchainTypes,
                                const QString &profileName = QString())
{
    const QString machineName = gccMachineName(compilerFilePath);
    const QStringList compilerTriplet = machineName.split(QLatin1Char('-'));
    const bool isMingw = toolchainTypes.contains(QLatin1String("mingw"));
    const bool isClang = toolchainTypes.contains(QLatin1String("clang"));

    if (isMingw && !validMinGWMachines().contains(machineName)) {
        throw qbs::ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.")
                .arg(machineName));
    } else if (compilerTriplet.count() < 2) {
        throw qbs::ErrorInfo(Tr::tr("Architecture of compiler for platform '%1' at '%2' not understood.")
                             .arg(machineName, compilerFilePath));
    }

    Profile profile(!profileName.isEmpty() ? profileName : machineName, settings);
    profile.removeProfile();
    if (isMingw) {
        profile.setValue(QLatin1String("qbs.targetOS"), QStringList(QLatin1String("windows")));
    }

    const QString compilerName = QFileInfo(compilerFilePath).fileName();
    QString toolchainPrefix;
    if (compilerName.contains(QLatin1Char('-'))) {
        QStringList nameParts = compilerName.split(QLatin1Char('-'));
        profile.setValue(QLatin1String("cpp.compilerName"), nameParts.takeLast());
        toolchainPrefix = nameParts.join(QLatin1String("-")) + QLatin1Char('-');
        profile.setValue(QLatin1String("cpp.toolchainPrefix"), toolchainPrefix);
    }
    profile.setValue(QLatin1String("cpp.linkerName"),
                     isClang ? QLatin1String("clang++") : QLatin1String("g++"));
    setCommonProperties(profile, compilerFilePath, toolchainPrefix, toolchainTypes,
                        compilerTriplet.first());

    // Check whether auxiliary tools reside within the toolchain's install path.
    // This might not be the case when using icecc or another compiler wrapper.
    const QString compilerDirPath = QFileInfo(compilerFilePath).absolutePath();
    const ToolPathSetup toolPathSetup(&profile, compilerDirPath, toolchainPrefix);
    toolPathSetup.apply(QLatin1String("ar"), QLatin1String("cpp.archiverPath"));
    toolPathSetup.apply(QLatin1String("nm"), QLatin1String("cpp.nmPath"));

    qStdout << Tr::tr("Profile '%1' created for '%2'.").arg(profile.name(), compilerFilePath)
            << endl;
    return profile;
}

static void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compilerName)
{
    qStdout << Tr::tr("Trying to detect %1...").arg(compilerName) << endl;

    const QString crossCompilePrefix = QString::fromLocal8Bit(qgetenv("CROSS_COMPILE"));
    const QString compilerFilePath = findExecutable(crossCompilePrefix + compilerName);
    if (!QFileInfo(compilerFilePath).exists()) {
        qStderr << Tr::tr("%1 not found.").arg(compilerName) << endl;
        return;
    }
    const QString profileName = QFileInfo(compilerFilePath).completeBaseName();
    const QStringList toolchainTypes = toolchainTypeFromCompilerName(compilerName);
    profiles << createGccProfile(compilerFilePath, settings, toolchainTypes, profileName);
}

static void mingwProbe(Settings *settings, QList<Profile> &profiles)
{
    // List of possible compiler binary names for this platform
    QStringList compilerNames;
    if (HostOsInfo::isWindowsHost()) {
        compilerNames << QLatin1String("gcc");
    } else {
        foreach (const QString &machineName, validMinGWMachines()) {
            compilerNames << machineName + QLatin1String("-gcc");
        }
    }

    foreach (const QString &compilerName, compilerNames) {
        const QString gccPath
                = findExecutable(HostOsInfo::appendExecutableSuffix(compilerName));
        if (!gccPath.isEmpty())
            profiles << createGccProfile(gccPath, settings,
                                         completeToolchainList(QLatin1String("mingw")));
    }
}

void probe(Settings *settings)
{
    QList<Profile> profiles;
    if (HostOsInfo::isWindowsHost()) {
        msvcProbe(settings, profiles);
    } else {
        gccProbe(settings, profiles, QLatin1String("gcc"));
        gccProbe(settings, profiles, QLatin1String("clang"));

        if (HostOsInfo::isOsxHost()) {
            xcodeProbe(settings, profiles);
        }
    }

    mingwProbe(settings, profiles);

    if (profiles.isEmpty()) {
        qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << endl;
    } else if (profiles.count() == 1 && settings->defaultProfile().isEmpty()) {
        const QString profileName = profiles.first().name();
        qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << endl;
        settings->setValue(QLatin1String("defaultProfile"), profileName);
    }
}

void createProfile(const QString &profileName, const QString &toolchainType,
                   const QString &compilerFilePath, Settings *settings)
{
    QFileInfo compiler(compilerFilePath);
    if (compilerFilePath == compiler.fileName() && !compiler.exists())
        compiler = QFileInfo(findExecutable(compilerFilePath));

    if (!compiler.exists()) {
        throw qbs::ErrorInfo(Tr::tr("Compiler '%1' not found")
                             .arg(compilerFilePath));
    }

    QStringList toolchainTypes;
    if (toolchainType.isEmpty())
        toolchainTypes = toolchainTypeFromCompilerName(compiler.fileName());
    else
        toolchainTypes = completeToolchainList(toolchainType);

    if (toolchainTypes.contains(QLatin1String("msvc"))) {
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: MSVC toolchains can only be created "
                                    "via the auto-detection mechanism."));
    }

    if (toolchainTypes.contains(QLatin1String("gcc")))
        createGccProfile(compiler.absoluteFilePath(), settings, toolchainTypes, profileName);
    else
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type."));
}
<commit_msg>Update mingw crosscompiler detection for mxe<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** 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://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, 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 "probe.h"

#include "msvcprobe.h"
#include "xcodeprobe.h"

#include <logging/translator.h>
#include <tools/architectures.h>
#include <tools/error.h>
#include <tools/hostosinfo.h>
#include <tools/profile.h>
#include <tools/scripttools.h>
#include <tools/settings.h>

#include <QDir>
#include <QFileInfo>
#include <QProcess>
#include <QStringList>
#include <QTextStream>

#include <cstdio>

using namespace qbs;
using Internal::HostOsInfo;
using Internal::Tr;

static QTextStream qStdout(stdout);
static QTextStream qStderr(stderr);

static QString findExecutable(const QString &fileName)
{
    const QString path = QString::fromLocal8Bit(qgetenv("PATH"));
    foreach (const QString &ppath, path.split(HostOsInfo::pathListSeparator())) {
        const QString fullPath = ppath + QLatin1Char('/') + fileName;
        if (QFileInfo(fullPath).exists())
            return QDir::cleanPath(fullPath);
    }
    return QString();
}

static QString qsystem(const QString &exe, const QStringList &args = QStringList())
{
    QProcess p;
    p.setProcessChannelMode(QProcess::MergedChannels);
    p.start(exe, args);
    if (!p.waitForStarted()) {
        throw qbs::ErrorInfo(Tr::tr("Failed to start compiler '%1': %2")
                             .arg(exe, p.errorString()));
    }
    if (!p.waitForFinished() || p.exitCode() != 0)
        throw qbs::ErrorInfo(Tr::tr("Failed to run compiler '%1': %2").arg(exe, p.errorString()));
    return QString::fromLocal8Bit(p.readAll());
}

static QStringList validMinGWMachines()
{
    // List of MinGW machine names (gcc -dumpmachine) recognized by Qbs
    return QStringList()
            << QLatin1String("mingw32") << QLatin1String("mingw64")
            << QLatin1String("i686-w64-mingw32") << QLatin1String("x86_64-w64-mingw32")
            << QLatin1String("i686-w64-mingw32.shared") << QLatin1String("x86_64-w64-mingw32.shared")
            << QLatin1String("i686-w64-mingw32.static") << QLatin1String("x86_64-w64-mingw32.static")
            << QLatin1String("i586-mingw32msvc") << QLatin1String("amd64-mingw32msvc");
}

static QStringList completeToolchainList(const QString &toolchainName)
{
    QStringList toolchains(toolchainName);
    if (toolchainName == QLatin1String("clang"))
        toolchains << completeToolchainList(QLatin1String("llvm"));
    else if (toolchainName == QLatin1String("llvm") ||
             toolchainName == QLatin1String("mingw")) {
        toolchains << completeToolchainList(QLatin1String("gcc"));
    }
    return toolchains;
}

static QStringList toolchainTypeFromCompilerName(const QString &compilerName)
{
    if (compilerName == QLatin1String("cl.exe"))
        return completeToolchainList(QLatin1String("msvc"));
    foreach (const QString &type, (QStringList() << QLatin1String("clang") << QLatin1String("llvm")
                                                 << QLatin1String("mingw") << QLatin1String("gcc")))
        if (compilerName.contains(type))
            return completeToolchainList(type);
    return QStringList();
}

static QString gccMachineName(const QString &compilerFilePath)
{
    return qsystem(compilerFilePath, QStringList() << QLatin1String("-dumpmachine")).trimmed();
}

static void setupCompilerPathByLanguage(Profile &profile, const QStringList &toolchainTypes,
        const QString &toolchainInstallPath, const QString &toolchainPrefix)
{
    QVariantMap m;
    if (toolchainTypes.contains("clang")) {
        m["c"] = m["objc"] = QLatin1String("clang");
        m["cpp"] = m["objcpp"] = QLatin1String("clang++");
    } else if (toolchainTypes.contains("gcc")) {
        m["c"] = m["objc"] = QLatin1String("gcc");
        m["cpp"] = m["objcpp"] = QLatin1String("g++");
    } else {
        qDebug("WARNING: unexpected toolchain %s", qPrintable(toJSLiteral(toolchainTypes)));
        return;
    }

    const QString toolchainPathPrefix = toolchainInstallPath + QLatin1Char('/') + toolchainPrefix;
    for (QVariantMap::iterator it = m.begin(); it != m.end();) {
        const QString filePath = HostOsInfo::appendExecutableSuffix(toolchainPathPrefix
                                                                    + it.value().toString());
        if (QFile::exists(filePath)) {
            it.value() = filePath;
            ++it;
            continue;
        }
        qDebug("WARNING: Compiler %s for file tag %s not found.",
               qPrintable(QDir::toNativeSeparators(filePath)), qPrintable(it.key()));
        it = m.erase(it);
    }
    if (!m.isEmpty())
        profile.setValue(QLatin1String("cpp.compilerPathByLanguage"), m);
}

static void setCommonProperties(Profile &profile, const QString &compilerFilePath,
        const QString &toolchainPrefix, const QStringList &toolchainTypes,
        const QString &architecture)
{
    QFileInfo cfi(compilerFilePath);
    const QString toolchainInstallPath = cfi.absolutePath();
    profile.setValue(QLatin1String("cpp.toolchainInstallPath"), toolchainInstallPath);
    profile.setValue(QLatin1String("cpp.compilerName"), cfi.fileName());
    profile.setValue(QLatin1String("qbs.toolchain"), toolchainTypes);
    profile.setValue(QLatin1String("qbs.architecture"), canonicalArchitecture(architecture));
    profile.setValue(QLatin1String("qbs.endianness"), defaultEndianness(architecture));
    setupCompilerPathByLanguage(profile, toolchainTypes, toolchainInstallPath, toolchainPrefix);
}

class ToolPathSetup
{
public:
    ToolPathSetup(Profile *profile, const QString &path, const QString &toolchainPrefix)
        : m_profile(profile), m_compilerDirPath(path), m_toolchainPrefix(toolchainPrefix)
    {
    }

    void apply(const QString &toolName, const QString &propertyName) const
    {
        QString toolFileName = m_toolchainPrefix + HostOsInfo::appendExecutableSuffix(toolName);
        if (QFile::exists(m_compilerDirPath + QLatin1Char('/') + toolFileName))
            return;
        const QString toolFilePath = findExecutable(toolFileName);
        if (toolFilePath.isEmpty()) {
            qWarning("%s", qPrintable(
                         QString(QLatin1String("'%1' exists neither in '%2' nor in PATH."))
                            .arg(toolFileName, m_compilerDirPath)));
        }
        m_profile->setValue(propertyName, toolFilePath);
    }

private:
    Profile * const m_profile;
    const QString &m_compilerDirPath;
    const QString &m_toolchainPrefix;
};

static Profile createGccProfile(const QString &compilerFilePath, Settings *settings,
                                const QStringList &toolchainTypes,
                                const QString &profileName = QString())
{
    const QString machineName = gccMachineName(compilerFilePath);
    const QStringList compilerTriplet = machineName.split(QLatin1Char('-'));
    const bool isMingw = toolchainTypes.contains(QLatin1String("mingw"));
    const bool isClang = toolchainTypes.contains(QLatin1String("clang"));

    if (isMingw && !validMinGWMachines().contains(machineName)) {
        throw qbs::ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.")
                .arg(machineName));
    } else if (compilerTriplet.count() < 2) {
        throw qbs::ErrorInfo(Tr::tr("Architecture of compiler for platform '%1' at '%2' not understood.")
                             .arg(machineName, compilerFilePath));
    }

    Profile profile(!profileName.isEmpty() ? profileName : machineName, settings);
    profile.removeProfile();
    if (isMingw) {
        profile.setValue(QLatin1String("qbs.targetOS"), QStringList(QLatin1String("windows")));
    }

    const QString compilerName = QFileInfo(compilerFilePath).fileName();
    QString toolchainPrefix;
    if (compilerName.contains(QLatin1Char('-'))) {
        QStringList nameParts = compilerName.split(QLatin1Char('-'));
        profile.setValue(QLatin1String("cpp.compilerName"), nameParts.takeLast());
        toolchainPrefix = nameParts.join(QLatin1String("-")) + QLatin1Char('-');
        profile.setValue(QLatin1String("cpp.toolchainPrefix"), toolchainPrefix);
    }
    profile.setValue(QLatin1String("cpp.linkerName"),
                     isClang ? QLatin1String("clang++") : QLatin1String("g++"));
    setCommonProperties(profile, compilerFilePath, toolchainPrefix, toolchainTypes,
                        compilerTriplet.first());

    // Check whether auxiliary tools reside within the toolchain's install path.
    // This might not be the case when using icecc or another compiler wrapper.
    const QString compilerDirPath = QFileInfo(compilerFilePath).absolutePath();
    const ToolPathSetup toolPathSetup(&profile, compilerDirPath, toolchainPrefix);
    toolPathSetup.apply(QLatin1String("ar"), QLatin1String("cpp.archiverPath"));
    toolPathSetup.apply(QLatin1String("nm"), QLatin1String("cpp.nmPath"));

    qStdout << Tr::tr("Profile '%1' created for '%2'.").arg(profile.name(), compilerFilePath)
            << endl;
    return profile;
}

static void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compilerName)
{
    qStdout << Tr::tr("Trying to detect %1...").arg(compilerName) << endl;

    const QString crossCompilePrefix = QString::fromLocal8Bit(qgetenv("CROSS_COMPILE"));
    const QString compilerFilePath = findExecutable(crossCompilePrefix + compilerName);
    if (!QFileInfo(compilerFilePath).exists()) {
        qStderr << Tr::tr("%1 not found.").arg(compilerName) << endl;
        return;
    }
    const QString profileName = QFileInfo(compilerFilePath).completeBaseName();
    const QStringList toolchainTypes = toolchainTypeFromCompilerName(compilerName);
    profiles << createGccProfile(compilerFilePath, settings, toolchainTypes, profileName);
}

static void mingwProbe(Settings *settings, QList<Profile> &profiles)
{
    // List of possible compiler binary names for this platform
    QStringList compilerNames;
    if (HostOsInfo::isWindowsHost()) {
        compilerNames << QLatin1String("gcc");
    } else {
        foreach (const QString &machineName, validMinGWMachines()) {
            compilerNames << machineName + QLatin1String("-gcc");
        }
    }

    foreach (const QString &compilerName, compilerNames) {
        const QString gccPath
                = findExecutable(HostOsInfo::appendExecutableSuffix(compilerName));
        if (!gccPath.isEmpty())
            profiles << createGccProfile(gccPath, settings,
                                         completeToolchainList(QLatin1String("mingw")));
    }
}

void probe(Settings *settings)
{
    QList<Profile> profiles;
    if (HostOsInfo::isWindowsHost()) {
        msvcProbe(settings, profiles);
    } else {
        gccProbe(settings, profiles, QLatin1String("gcc"));
        gccProbe(settings, profiles, QLatin1String("clang"));

        if (HostOsInfo::isOsxHost()) {
            xcodeProbe(settings, profiles);
        }
    }

    mingwProbe(settings, profiles);

    if (profiles.isEmpty()) {
        qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << endl;
    } else if (profiles.count() == 1 && settings->defaultProfile().isEmpty()) {
        const QString profileName = profiles.first().name();
        qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << endl;
        settings->setValue(QLatin1String("defaultProfile"), profileName);
    }
}

void createProfile(const QString &profileName, const QString &toolchainType,
                   const QString &compilerFilePath, Settings *settings)
{
    QFileInfo compiler(compilerFilePath);
    if (compilerFilePath == compiler.fileName() && !compiler.exists())
        compiler = QFileInfo(findExecutable(compilerFilePath));

    if (!compiler.exists()) {
        throw qbs::ErrorInfo(Tr::tr("Compiler '%1' not found")
                             .arg(compilerFilePath));
    }

    QStringList toolchainTypes;
    if (toolchainType.isEmpty())
        toolchainTypes = toolchainTypeFromCompilerName(compiler.fileName());
    else
        toolchainTypes = completeToolchainList(toolchainType);

    if (toolchainTypes.contains(QLatin1String("msvc"))) {
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: MSVC toolchains can only be created "
                                    "via the auto-detection mechanism."));
    }

    if (toolchainTypes.contains(QLatin1String("gcc")))
        createGccProfile(compiler.absoluteFilePath(), settings, toolchainTypes, profileName);
    else
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type."));
}
<|endoftext|>


<commit_before>// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "at_exit.h"
#include "atomic_list.h"
#include <thread>
#include <unordered_set>

using autowiring::atomic_list;

struct HoldsInt :
  autowiring::callable_base
{
  HoldsInt(int value) : value(value) {}
  int value;
  operator int(void) const { return value; }
};

TEST(AtomicListTest, SimpleInsertion) {
  atomic_list l;
  uint32_t ids[] = {
    l.push<HoldsInt>(55),
    l.push<HoldsInt>(56),
    l.push<HoldsInt>(57)
  };
  ASSERT_EQ(ids[0], ids[1]);
  ASSERT_EQ(ids[0], ids[2]);

  auto e = l.release<HoldsInt>();
  auto q = e.begin();

  for (size_t i = 55; i <= 57; i++) {
    ASSERT_NE(e.end(), q) << "Unexpected end of list encountered";
    EXPECT_EQ(i, *q) << "List retrieved in the wrong order";
    ++q;
  }
}

TEST(AtomicListTest, IdIncrement) {
  atomic_list l;
  uint32_t id1 = l.push<HoldsInt>(101);
  auto e = l.release<HoldsInt>();
  uint32_t id2 = l.push<HoldsInt>(102);
  ASSERT_NE(id1, id2) << "Identifier not incremented as expected";
}

TEST(AtomicListTest, IdIncrementPathological) {
  enum class Owner { None, Consumer, Producer };

  atomic_list l;
  std::unordered_set<int> S;
  volatile bool proceed = false;

  // Initial owner is the consumer:
  std::atomic<Owner> owner{ Owner::Consumer };

  std::thread consumer([&] {
    owner = Owner::None;

    while (proceed) {
      Owner exp;
      do exp = Owner::None;
      while(!owner.compare_exchange_weak(exp, Owner::Consumer));
      auto x = MakeAtExit([&owner] { owner = Owner::None; });

      auto f = l.release<HoldsInt>();
      for(int value : f)
        S.insert(value);
    }
  });
  auto x = MakeAtExit([&] {
    proceed = false;
    consumer.join();
  });

  // Drive items into the list and see if we can rip them back:
  for (size_t i = 10000; i--;) {
    uint32_t insertedID = l.push<HoldsInt>(i);

    Owner exp;
    do exp = Owner::None;
    while (!owner.compare_exchange_weak(exp, Owner::Producer));
    auto x = MakeAtExit([&owner] { owner = Owner::None; });

    auto curChainID = l.chain_id();
    if (curChainID == insertedID)
      // Still in the list, should not have been observed by the consumer yet
      ASSERT_EQ(0UL, S.count(i)) << "Chain ID was not updated, but element was found in consumer set";
    else
      // Not in the list, must be in the set
      ASSERT_EQ(1UL, S.count(i)) << "Chain ID was updated, but element was not found in consumer set";
  }
}
<commit_msg>Use a sweep instead of a set<commit_after>// Copyright (C) 2012-2015 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "at_exit.h"
#include "atomic_list.h"
#include <thread>

using autowiring::atomic_list;

struct HoldsInt :
  autowiring::callable_base
{
  HoldsInt(int value) : value(value) {}
  int value;
  operator int(void) const { return value; }
};

TEST(AtomicListTest, SimpleInsertion) {
  atomic_list l;
  uint32_t ids[] = {
    l.push<HoldsInt>(55),
    l.push<HoldsInt>(56),
    l.push<HoldsInt>(57)
  };
  ASSERT_EQ(ids[0], ids[1]);
  ASSERT_EQ(ids[0], ids[2]);

  auto e = l.release<HoldsInt>();
  auto q = e.begin();

  for (size_t i = 55; i <= 57; i++) {
    ASSERT_NE(e.end(), q) << "Unexpected end of list encountered";
    EXPECT_EQ(i, *q) << "List retrieved in the wrong order";
    ++q;
  }
}

TEST(AtomicListTest, IdIncrement) {
  atomic_list l;
  uint32_t id1 = l.push<HoldsInt>(101);
  auto e = l.release<HoldsInt>();
  uint32_t id2 = l.push<HoldsInt>(102);
  ASSERT_NE(id1, id2) << "Identifier not incremented as expected";
}

TEST(AtomicListTest, IdIncrementPathological) {
  enum class Owner { None, Consumer, Producer };

  atomic_list l;
  volatile int latest = -1;
  volatile bool proceed = false;

  // Initial owner is the consumer:
  std::atomic<Owner> owner{ Owner::Consumer };

  std::thread consumer([&] {
    owner = Owner::None;

    while (proceed) {
      Owner exp;
      do exp = Owner::None;
      while(!owner.compare_exchange_weak(exp, Owner::Consumer));
      auto x = MakeAtExit([&owner] { owner = Owner::None; });

      auto f = l.release<HoldsInt>();
      for (int value : f)
        latest = value;
    }
  });
  auto x = MakeAtExit([&] {
    proceed = false;
    consumer.join();
  });

  // Drive items into the list and see if we can rip them back:
  for (int i = 0; i < 10000; i++) {
    uint32_t insertedID = l.push<HoldsInt>(i);

    Owner exp;
    do exp = Owner::None;
    while (!owner.compare_exchange_weak(exp, Owner::Producer));
    auto x = MakeAtExit([&owner] { owner = Owner::None; });

    auto curChainID = l.chain_id();
    if (curChainID == insertedID)
      // Still in the list, should not have been observed by the consumer yet
      ASSERT_LT(latest, i) << "Chain ID was not updated, but element was found in consumer set";
    else
      // Not in the list, must be in the set
      ASSERT_GE(latest, i) << "Chain ID was updated, but element was not found in consumer set";
  }
}
<|endoftext|>


<commit_before>#include "LogicController.h"

LogicController::LogicController() {

  logicState = LOGIC_STATE_INTERRUPT;
  processState = PROCCESS_STATE_SEARCHING;

  ProcessData();

  control_queue = priority_queue<PrioritizedController>();

}

LogicController::~LogicController() {}

void LogicController::Reset() {

  std::cout << "LogicController.Reset()" << std::endl;
  logicState = LOGIC_STATE_INTERRUPT;
  processState = PROCCESS_STATE_SEARCHING;

  ProcessData();

  control_queue = priority_queue<PrioritizedController>();
}

//***********************************************************************************************************************
//This function is called every 1/10th second by the ROSAdapter
//The logical flow if the behaviours is controlled here by using a interrupt, haswork, priority queue system.
Result LogicController::DoWork() {
  Result result;

  //first a loop runs through all the controllers who have a priority of 0 or above witht he largest number being
  //most important. A priority of less than 0 is an ignored controller use -1 for standards sake.
  //if any controller needs and interrupt the logic state is changed to interrupt
  for(PrioritizedController cntrlr : prioritizedControllers) {
    if(cntrlr.controller->ShouldInterrupt() && cntrlr.priority >= 0)
      {
	logicState = LOGIC_STATE_INTERRUPT;
	//do not break all shouldInterupts may need calling in order to properly pre-proccess data.
      }
  }

  //logic state switch
  switch(logicState) {

  //when an interrupt has been thorwn or there are no pending control_queue.top().actions logic controller is in this state.
  case LOGIC_STATE_INTERRUPT: {
    //Reset the control queue
    control_queue = priority_queue<PrioritizedController>();

    //check what controllers have work to do all that say yes will be added to the priority queue.
    for(PrioritizedController cntrlr : prioritizedControllers) {
      if(cntrlr.controller->HasWork()) {
        if (cntrlr.priority < 0) {
          continue;
        }
        else {
          control_queue.push(cntrlr);
        }
      }
    }

    //if no controlers have work report this to ROS Adapter and do nothing.
    if(control_queue.empty()) {
      result.type = behavior;
      result.b = wait;
      break;
    }
    else {
      //default result state if someone has work this safe gaurds against faulty result types
      result.b = noChange;
    }

    //take the top member of the priority queue and run their do work function.
    result = control_queue.top().controller->DoWork();

    //anaylyze the result that was returned and do state changes accordingly
    //behavior types are used to indicate behavior changes of some form
    if(result.type == behavior) {

      //ask for an external reset so the state of the controller is preserved untill after it has returned a result and
      //gotten a chance to communicate with other controllers
      if (result.reset) {
        controllerInterconnect(); //allow controller to communicate state data before it is reset
        control_queue.top().controller->Reset();
      }

      //ask for the procces state to change to the next state or loop around to the begining
      if(result.b == nextProcess) {
        if (processState == _LAST - 1) {
          processState = _FIRST;
        }
        else {
          processState = (ProcessState)((int)processState + 1);
        }
      }
      //ask for the procces state to change to the previouse state or loop around to the end
      else if(result.b == prevProcess) {
        if (processState == _FIRST) {
          processState = (ProcessState)((int)_LAST - 1);
        }
        else {
          processState = (ProcessState)((int)processState - 1);
        }
      }

      //update the priorites of the controllers based upon the new process state.
      if (result.b == nextProcess || result.b == prevProcess) {
        ProcessData();
        result.b = wait;
        driveController.Reset(); //it is assumed that the drive controller may be in a bad state if interrupted so reset it
      }
      break;
    }

    //precision driving result types are when a controller wants direct command of the robots actuators
    //logic controller facilitates the command pass through in the LOGIC_STATE_PRECISION_COMMAND switch case
    else if(result.type == precisionDriving) {

      logicState = LOGIC_STATE_PRECISION_COMMAND;
      break;

    }

    //waypoints are also a pass through facilitated command but with a slightly diffrent overhead
    //they are handled in the LOGIC_STATE_WAITING switch case
    else if(result.type == waypoint) {

      logicState = LOGIC_STATE_WAITING;
      driveController.SetResultData(result);
      //fall through on purpose
    }

  } //end of interupt case***************************************************************************************

    //this case is primarly when logic controller is waiting for drive controller to reach its last waypoint
  case LOGIC_STATE_WAITING: {
    //ask drive controller how to drive
    //commands to be passed the ROS Adapter as left and right wheel PWM values in the result struct are returned
    result = driveController.DoWork();

    //when out of waypoints drive controller will through an interrupt however unlike other controllers
    //drive controller is not on the priority queue so it must be checked here
    if (result.type == behavior) {
      if(driveController.ShouldInterrupt()) {
        logicState = LOGIC_STATE_INTERRUPT;
      }
    }
    break;
  }//end of waiting case*****************************************************************************************

    //used for precision driving pass through
  case LOGIC_STATE_PRECISION_COMMAND: {

    //unlike waypoints precision commands change every update tick so we ask the
    //controller for new commands on every update tick.
    result = control_queue.top().controller->DoWork();

    //pass the driving commands to the drive controller so it can interpret them
    driveController.SetResultData(result);

    //the interoreted commands are turned into properinitial_spiral_offset motor commands to be passed the ROS Adapter
    //as left and right wheel PWM values in the result struct.
    result = driveController.DoWork();
    break;

  }//end of precision case****************************************************************************************
  }//end switch statment******************************************************************************************

   // bad! causes node to crash
   // cout << "logic state " << logicState << " top controller " << control_queue.top().priority << " Proccess " << processState <<endl;

  //now using proccess logic allow the controller to communicate data between eachother
  controllerInterconnect();

  //give the ROSAdapter the final decision on how it should drive
  return result;
}

void LogicController::UpdateData()
{

}

void LogicController::ProcessData()
{

  //this controller priority is used when searching
  if (processState == PROCCESS_STATE_SEARCHING)
  {
    prioritizedControllers = {
      PrioritizedController{0, (Controller*)(&searchController)},
      PrioritizedController{10, (Controller*)(&obstacleController)},
      PrioritizedController{15, (Controller*)(&pickUpController)},
      PrioritizedController{5, (Controller*)(&range_controller)},
      PrioritizedController{-1, (Controller*)(&dropOffController)},
      PrioritizedController{-1, (Controller*)(&manualWaypointController)}
    };
  }

  //this priority is used when returning a target to the center collection zone
  else if (processState  == PROCCESS_STATE_TARGET_PICKEDUP)
  {
    prioritizedControllers = {
    PrioritizedController{-1, (Controller*)(&searchController)},
    PrioritizedController{15, (Controller*)(&obstacleController)},
    PrioritizedController{-1, (Controller*)(&pickUpController)},
    PrioritizedController{10, (Controller*)(&range_controller)},
    PrioritizedController{1, (Controller*)(&dropOffController)},
    PrioritizedController{-1, (Controller*)(&manualWaypointController)}
    };
  }
  //this priority is used when returning a target to the center collection zone
  else if (processState  == PROCCESS_STATE_DROP_OFF)
  {
    prioritizedControllers = {
      PrioritizedController{-1, (Controller*)(&searchController)},
      PrioritizedController{-1, (Controller*)(&obstacleController)},
      PrioritizedController{-1, (Controller*)(&pickUpController)},
      PrioritizedController{10, (Controller*)(&range_controller)},
      PrioritizedController{1, (Controller*)(&dropOffController)},
      PrioritizedController{-1, (Controller*)(&manualWaypointController)}
    };
  }
  else if (processState == PROCESS_STATE_MANUAL) {
    // under manual control only the manual waypoint controller is active
    prioritizedControllers = {
      PrioritizedController{-1, (Controller*)(&searchController)},
      PrioritizedController{-1, (Controller*)(&obstacleController)},
      PrioritizedController{-1, (Controller*)(&pickUpController)},
      PrioritizedController{-1, (Controller*)(&range_controller)},
      PrioritizedController{-1, (Controller*)(&dropOffController)},
      PrioritizedController{5,  (Controller*)(&manualWaypointController)}
    };
  }
}

bool LogicController::ShouldInterrupt()
{
  ProcessData();

  return false;
}

bool LogicController::HasWork()
{
  return false;
}

void LogicController::controllerInterconnect()
{

  if (processState == PROCCESS_STATE_SEARCHING)
  {

    //obstacle needs to know if the center ultrasound should be ignored
    if(pickUpController.GetIgnoreCenter())
    {
      obstacleController.setIgnoreCenterSonar();
    }

    //pickup controller annouces it has pickedup a target
    if(pickUpController.GetTargetHeld())
    {
      dropOffController.SetTargetPickedUp();
      obstacleController.setTargetHeld();
      searchController.SetSuccesfullPickup();
    }
  }

  //ask if drop off has released the target from the claws yet
  if (!dropOffController.HasTarget())
  {
    obstacleController.setTargetHeldClear();
  }

  //obstacle controller is running driveController needs to clear its waypoints
  if(obstacleController.getShouldClearWaypoints())
  {
    driveController.Reset();
  }

}

// Recieves position in the world inertial frame (should rename to SetOdomPositionData)
void LogicController::SetPositionData(Point currentLocation)
{
  searchController.SetCurrentLocation(currentLocation);
  dropOffController.SetCurrentLocation(currentLocation);
  obstacleController.setCurrentLocation(currentLocation);
  driveController.SetCurrentLocation(currentLocation);
  manualWaypointController.SetCurrentLocation(currentLocation);
}

// Recieves position in the world frame with global data (GPS)
void LogicController::SetMapPositionData(Point currentLocation)
{
  range_controller.setCurrentLocation(currentLocation);
}

void LogicController::SetVelocityData(float linearVelocity, float angularVelocity)
{
  driveController.SetVelocityData(linearVelocity,angularVelocity);
}

void LogicController::SetMapVelocityData(float linearVelocity, float angularVelocity)
{

}

void LogicController::SetAprilTags(vector<Tag> tags)
{
  pickUpController.SetTagData(tags);
  obstacleController.setTagData(tags);
  dropOffController.SetTargetData(tags);
}

void LogicController::SetSonarData(float left, float center, float right)
{
  pickUpController.SetSonarData(center);
  obstacleController.setSonarData(left,center,right);
}

// Called once by RosAdapter in guarded init
void LogicController::SetCenterLocationOdom(Point centerLocationOdom)
{
  searchController.SetCenterLocation(centerLocationOdom);
  dropOffController.SetCenterLocation(centerLocationOdom);
}

void LogicController::AddManualWaypoint(Point manualWaypoint, int waypoint_id)
{
  manualWaypointController.AddManualWaypoint(manualWaypoint, waypoint_id);
}

void LogicController::RemoveManualWaypoint(int waypoint_id)
{
  manualWaypointController.RemoveManualWaypoint(waypoint_id);
}

std::vector<int> LogicController::GetClearedWaypoints()
{
  return manualWaypointController.ReachedWaypoints();
}

void LogicController::setVirtualFenceOn( RangeShape* range )
{
  range_controller.setRangeShape(range);
  range_controller.setEnabled(true);
}

void LogicController::setVirtualFenceOff()
{
  range_controller.setEnabled(false);
}

void LogicController::SetCenterLocationMap(Point centerLocationMap)
{

}

void LogicController::SetCurrentTimeInMilliSecs( long int time )
{
  current_time = time;
  dropOffController.SetCurrentTimeInMilliSecs( time );
  pickUpController.SetCurrentTimeInMilliSecs( time );
  obstacleController.setCurrentTimeInMilliSecs( time );
}

void LogicController::SetModeAuto() {
  if(processState == PROCESS_STATE_MANUAL) {
    // only do something if we are in manual mode
    this->Reset();
    manualWaypointController.Reset();
  }
}
void LogicController::SetModeManual()
{
  if(processState != PROCESS_STATE_MANUAL) {
    logicState = LOGIC_STATE_INTERRUPT;
    processState = PROCESS_STATE_MANUAL;
    ProcessData();
    control_queue = priority_queue<PrioritizedController>();
    driveController.Reset();
  }
}
<commit_msg>added comments for .cpp implementation file<commit_after>#include "LogicController.h"

LogicController::LogicController() {

  logicState = LOGIC_STATE_INTERRUPT;
  processState = PROCCESS_STATE_SEARCHING;

  ProcessData();

  control_queue = priority_queue<PrioritizedController>();

}

LogicController::~LogicController() {}

void LogicController::Reset() {

  std::cout << "LogicController.Reset()" << std::endl;
  logicState = LOGIC_STATE_INTERRUPT;
  processState = PROCCESS_STATE_SEARCHING;

  ProcessData();

  control_queue = priority_queue<PrioritizedController>();
}

//******************************************************************************
// This function is called every 1/10th of a second by the ROSAdapter
// The logical flow if the behaviours is controlled here by using an interrupt,
// haswork, and priority queue system.
Result LogicController::DoWork()
{
  Result result;

  // First, a loop runs through all the controllers who have a priority of 0 or
  // above with the largest number being most important. A priority of less than
  // 0 is an ignored controller (we will use -1 as the standard for an ignored
  // controller). If any controller needs an interrupt, the logic state is
  // changed to interrupt
  for(PrioritizedController cntrlr : prioritizedControllers)
  {
    if(cntrlr.controller->ShouldInterrupt() && cntrlr.priority >= 0)
    {
      logicState = LOGIC_STATE_INTERRUPT;
      // Do not break out of the for loop! All shouldInterupts may need calling
      // in order to properly pre-proccess data.
    }
  }

  switch(logicState) {

  // ***************************************************************************
  // BEGIN LOGIC_STATE_INTERUPT
  // ***************************************************************************

  // Enter this state when an interrupt has been thrown or there are no pending
  // control_queue.top().actions.
  case LOGIC_STATE_INTERRUPT: {
    // Reset the control queue
    control_queue = priority_queue<PrioritizedController>();

    // Check what controllers have work to do.. Every controller, where
    // HasWork() == true, will be added to the priority queue.
    for(PrioritizedController cntrlr : prioritizedControllers) {
      if(cntrlr.controller->HasWork()) {
        if (cntrlr.priority < 0) {
          continue;
        }
        else {
          control_queue.push(cntrlr);
        }
      }
    }

    // If no controlers have work, report this to ROS Adapter and do nothing.
    if(control_queue.empty()) {
      result.type = behavior;
      result.b = wait;
      break;
    }
    else {
      // Default result state if someone has work. This safe gaurds against
      // faulty result types
      result.b = noChange;
    }

    // Take the top member of the priority queue and run its do work function.
    result = control_queue.top().controller->DoWork();

    // Analyze the result that was returned and do state changes accordingly.
    // Behavior types are used to indicate behavior changes.
    if(result.type == behavior) {

      // Ask for an external reset so the state of the controller is preserved
      // until after it has returned a result and gotten a chance to communicate
      // with other controllers.
      if (result.reset) {
        controllerInterconnect(); // Allow controller to communicate state data before it is reset.
        control_queue.top().controller->Reset();
      }

      // Ask for the procces state to change to the next state or loop around to the begining.
      //  enum ProcessState {
      //    _FIRST = 0,
      //    PROCCESS_STATE_SEARCHING = 0,
      //    PROCCESS_STATE_TARGET_PICKEDUP,
      //    PROCCESS_STATE_DROP_OFF,
      //    _LAST,
      //    PROCESS_STATE_MANUAL // robot is under manual control
      //  };
      if(result.b == nextProcess) {
        if (processState == _LAST - 1) {
          processState = _FIRST;
        }
        else {
          processState = (ProcessState)((int)processState + 1);
        }
      }
      // Ask for the procces state to change to the previouse state or loop around to the end.
      else if(result.b == prevProcess) {
        if (processState == _FIRST) {
          processState = (ProcessState)((int)_LAST - 1);
        }
        else {
          processState = (ProcessState)((int)processState - 1);
        }
      }

      // Update the priorites of the controllers based upon the new process state.
      if (result.b == nextProcess || result.b == prevProcess) {
        ProcessData();
        result.b = wait;
        driveController.Reset(); // It is assumed that the drive controller may
                                 // be in a bad state if interrupted, so reset it.
      }
      break;
    }

    // Precision driving result types are when a controller wants direct
    // command of the robots actuators. LogicController facilitates the command
    // pass through in the LOGIC_STATE_PRECISION_COMMAND switch case.
    else if(result.type == precisionDriving) {

      logicState = LOGIC_STATE_PRECISION_COMMAND;
      break;

    }

    // Waypoints are also a pass through facilitated command but with a slightly
    // diffrent overhead. They are handled in the LOGIC_STATE_WAITING switch case.
    else if(result.type == waypoint) {

      logicState = LOGIC_STATE_WAITING;
      driveController.SetResultData(result);
      // Fall through on purpose to "case LOGIC_STATE_WAITING:"
    }

  }
  // ***************************************************************************
  // END LOGIC_STATE_INTERUPT
  // ***************************************************************************

  // ***************************************************************************
  // BEGIN LOGIC_STATE_WAITING
  // ***************************************************************************

  // This case is primarly when logic controller is waiting for drive controller
  // to reach its last waypoint.
  case LOGIC_STATE_WAITING: {
    // Ask drive controller how to drive: specifically, return commands to be
    // passed to the ROS Adapter such as left and right wheel PWM values in the
    // result struct.
    result = driveController.DoWork();

    // When out of waypoints, the drive controller will throw an interrupt.
    // However, unlike other controllers, drive controller is not on the
    // priority queue so it must be checked here.
    if (result.type == behavior) {
      if(driveController.ShouldInterrupt()) {
        logicState = LOGIC_STATE_INTERRUPT;
      }
    }
    break;
  }
  // ***************************************************************************
  // END LOGIC_STATE_WAITING
  // ***************************************************************************

  // ***************************************************************************
  // BEGIN LOGIC_STATE_PRECISION_COMMAND
  // ***************************************************************************

    // Used for precision driving pass through.
  case LOGIC_STATE_PRECISION_COMMAND: {

    // Unlike waypoints, precision commands change every update tick, so we ask
    // the controller for new commands on every update tick.
    result = control_queue.top().controller->DoWork();

    // Pass the driving commands to the drive controller so it can interpret them.
    driveController.SetResultData(result);

    // The interpreted commands are turned into proper initial_spiral_offset
    // motor commands to be passed the ROS Adapter such as left and right wheel
    // PWM values in the result struct.
    result = driveController.DoWork();
    break;

  }
  // ***************************************************************************
  // END LOGIC_STATE_PRECISION_COMMAND
  // ***************************************************************************
}
// end switch statment *********************************************************

  // Allow the controllers to communicate data between each other,
  // depending on the processState.
  controllerInterconnect();

  // Give the ROSAdapter the final decision on how it should drive.
  return result;
}

void LogicController::UpdateData()
{
  // As the top level controller, there is no specific data that must
  // be updated in this controller. This function may be of greater use
  // and importance in lower level controllers.
}

void LogicController::ProcessData()
{

  // This controller priority is used when searching.
  if (processState == PROCCESS_STATE_SEARCHING)
  {
    prioritizedControllers = {
      PrioritizedController{0, (Controller*)(&searchController)},
      PrioritizedController{10, (Controller*)(&obstacleController)},
      PrioritizedController{15, (Controller*)(&pickUpController)},
      PrioritizedController{5, (Controller*)(&range_controller)},
      PrioritizedController{-1, (Controller*)(&dropOffController)},
      PrioritizedController{-1, (Controller*)(&manualWaypointController)}
    };
  }

  // This priority is used when returning a target to the center collection zone.
  else if (processState  == PROCCESS_STATE_TARGET_PICKEDUP)
  {
    prioritizedControllers = {
    PrioritizedController{-1, (Controller*)(&searchController)},
    PrioritizedController{15, (Controller*)(&obstacleController)},
    PrioritizedController{-1, (Controller*)(&pickUpController)},
    PrioritizedController{10, (Controller*)(&range_controller)},
    PrioritizedController{1, (Controller*)(&dropOffController)},
    PrioritizedController{-1, (Controller*)(&manualWaypointController)}
    };
  }

  // This priority is used when returning a target to the center collection zone.
  else if (processState  == PROCCESS_STATE_DROP_OFF)
  {
    prioritizedControllers = {
      PrioritizedController{-1, (Controller*)(&searchController)},
      PrioritizedController{-1, (Controller*)(&obstacleController)},
      PrioritizedController{-1, (Controller*)(&pickUpController)},
      PrioritizedController{10, (Controller*)(&range_controller)},
      PrioritizedController{1, (Controller*)(&dropOffController)},
      PrioritizedController{-1, (Controller*)(&manualWaypointController)}
    };
  }

  // Under manual control ONLY the manual waypoint controller is active.
  else if (processState == PROCESS_STATE_MANUAL) {
    prioritizedControllers = {
      PrioritizedController{-1, (Controller*)(&searchController)},
      PrioritizedController{-1, (Controller*)(&obstacleController)},
      PrioritizedController{-1, (Controller*)(&pickUpController)},
      PrioritizedController{-1, (Controller*)(&range_controller)},
      PrioritizedController{-1, (Controller*)(&dropOffController)},
      PrioritizedController{5,  (Controller*)(&manualWaypointController)}
    };
  }
}

bool LogicController::ShouldInterrupt()
{
  ProcessData();

  // The logic controller is the top level controller and will never have to
  // interrupt. It is only the lower level controllers that may need to interupt.
  return false;
}

bool LogicController::HasWork()
{
  // The LogicController class is a special case. It will never have work to
  // do because it is always handling the work of the other controllers.
  return false;
}

// This function will deal with inter-controller communication. Communication
// that needs to occur between specific low level controllers is done here.
//
// The type of communication may or may not depend on the processState.
//
//                       /<----> ControllerA
// LogicController <---->|                  \__ inter-controller communication
//                       |                  /
//                       \<----> ControllerB
void LogicController::controllerInterconnect()
{

  if (processState == PROCCESS_STATE_SEARCHING)
  {

    // Obstacle controller needs to know if the center ultrasound should be ignored.
    if(pickUpController.GetIgnoreCenter())
    {
      obstacleController.setIgnoreCenterSonar();
    }

    // Pickup controller anounces it has picked up a target.
    if(pickUpController.GetTargetHeld())
    {
      dropOffController.SetTargetPickedUp();
      obstacleController.setTargetHeld();
      searchController.SetSuccesfullPickup();
    }
  }

  // Ask if drop off has released the target from the gripper yet.
  if (!dropOffController.HasTarget())
  {
    obstacleController.setTargetHeldClear();
  }

  // Obstacle controller is running and driveController needs to clear its waypoints.
  if(obstacleController.getShouldClearWaypoints())
  {
    driveController.Reset();
  }

}

// Receives position in the world inertial frame (should rename to SetOdomPositionData).
void LogicController::SetPositionData(Point currentLocation)
{
  searchController.SetCurrentLocation(currentLocation);
  dropOffController.SetCurrentLocation(currentLocation);
  obstacleController.setCurrentLocation(currentLocation);
  driveController.SetCurrentLocation(currentLocation);
  manualWaypointController.SetCurrentLocation(currentLocation);
}

// Recieves position in the world frame with global data (GPS).
void LogicController::SetMapPositionData(Point currentLocation)
{
  range_controller.setCurrentLocation(currentLocation);
}

// Sets the velocity data for the driveController. This information is
// necessary so that the drive controller can update the velocity sent
// back to the RosAdapter correctly.
void LogicController::SetVelocityData(float linearVelocity, float angularVelocity)
{
  driveController.SetVelocityData(linearVelocity,angularVelocity);
}

void LogicController::SetMapVelocityData(float linearVelocity, float angularVelocity)
{
}

// Give the specified controllers a list of visible april tags.
void LogicController::SetAprilTags(vector<Tag> tags)
{
  pickUpController.SetTagData(tags);
  obstacleController.setTagData(tags);
  dropOffController.SetTargetData(tags);
}

// Give the specified controllers the sonar sensor values.
void LogicController::SetSonarData(float left, float center, float right)
{
  // The pickUpController only needs the center data in order to tell if
  // an april tag cube has been picked up correctly.
  pickUpController.SetSonarData(center);

  obstacleController.setSonarData(left,center,right);
}

// Called once by RosAdapter in guarded init.
void LogicController::SetCenterLocationOdom(Point centerLocationOdom)
{
  searchController.SetCenterLocation(centerLocationOdom);
  dropOffController.SetCenterLocation(centerLocationOdom);
}

void LogicController::AddManualWaypoint(Point manualWaypoint, int waypoint_id)
{
  manualWaypointController.AddManualWaypoint(manualWaypoint, waypoint_id);
}

void LogicController::RemoveManualWaypoint(int waypoint_id)
{
  manualWaypointController.RemoveManualWaypoint(waypoint_id);
}

std::vector<int> LogicController::GetClearedWaypoints()
{
  return manualWaypointController.ReachedWaypoints();
}

void LogicController::setVirtualFenceOn( RangeShape* range )
{
  range_controller.setRangeShape(range);
  range_controller.setEnabled(true);
}

void LogicController::setVirtualFenceOff()
{
  range_controller.setEnabled(false);
}

void LogicController::SetCenterLocationMap(Point centerLocationMap)
{
}

void LogicController::SetCurrentTimeInMilliSecs( long int time )
{
  current_time = time;
  dropOffController.SetCurrentTimeInMilliSecs( time );
  pickUpController.SetCurrentTimeInMilliSecs( time );
  obstacleController.setCurrentTimeInMilliSecs( time );
}

void LogicController::SetModeAuto() {
  if(processState == PROCESS_STATE_MANUAL) {
    // only do something if we are in manual mode
    this->Reset();
    manualWaypointController.Reset();
  }
}
void LogicController::SetModeManual()
{
  if(processState != PROCESS_STATE_MANUAL) {
    logicState = LOGIC_STATE_INTERRUPT;
    processState = PROCESS_STATE_MANUAL;
    ProcessData();
    control_queue = priority_queue<PrioritizedController>();
    driveController.Reset();
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. 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.

// This source file provides replacements for libc functions that we need. If
// we call the libc functions directly we risk crashing in the dynamic linker
// as it tries to resolve uncached PLT entries.

#include "src/common/linux/linux_libc_support.h"

#include <stddef.h>

extern "C" {

size_t my_strlen(const char* s) {
  size_t len = 0;
  while (*s++) len++;
  return len;
}

int my_strcmp(const char* a, const char* b) {
  for (;;) {
    if (*a < *b)
      return -1;
    else if (*a > *b)
      return 1;
    else if (*a == 0)
      return 0;
    a++;
    b++;
  }
}

int my_strncmp(const char* a, const char* b, size_t len) {
  for (size_t i = 0; i < len; ++i) {
    if (*a < *b)
      return -1;
    else if (*a > *b)
      return 1;
    else if (*a == 0)
      return 0;
    a++;
    b++;
  }

  return 0;
}

// Parse a non-negative integer.
//   result: (output) the resulting non-negative integer
//   s: a NUL terminated string
// Return true iff successful.
bool my_strtoui(int* result, const char* s) {
  if (*s == 0)
    return false;
  int r = 0;
  for (;; s++) {
    if (*s == 0)
      break;
    const int old_r = r;
    r *= 10;
    if (*s < '0' || *s > '9')
      return false;
    r += *s - '0';
    if (r < old_r)
      return false;
  }

  *result = r;
  return true;
}

// Return the length of the given, non-negative integer when expressed in base
// 10.
unsigned my_int_len(intmax_t i) {
  if (!i)
    return 1;

  int len = 0;
  while (i) {
    len++;
    i /= 10;
  }

  return len;
}

// Convert a non-negative integer to a string
//   output: (output) the resulting string is written here. This buffer must be
//     large enough to hold the resulting string. Call |my_int_len| to get the
//     required length.
//   i: the non-negative integer to serialise.
//   i_len: the length of the integer in base 10 (see |my_int_len|).
void my_itos(char* output, intmax_t i, unsigned i_len) {
  for (unsigned index = i_len; index; --index, i /= 10)
    output[index - 1] = '0' + (i % 10);
}

const char* my_strchr(const char* haystack, char needle) {
  while (*haystack && *haystack != needle)
    haystack++;
  if (*haystack == needle)
    return haystack;
  return (const char*) 0;
}

const char* my_strrchr(const char* haystack, char needle) {
  const char* ret = NULL;
  while (*haystack) {
    if (*haystack == needle)
      ret = haystack;
    haystack++;
  }
  return ret;
}

// Read a hex value
//   result: (output) the resulting value
//   s: a string
// Returns a pointer to the first invalid charactor.
const char* my_read_hex_ptr(uintptr_t* result, const char* s) {
  uintptr_t r = 0;

  for (;; ++s) {
    if (*s >= '0' && *s <= '9') {
      r <<= 4;
      r += *s - '0';
    } else if (*s >= 'a' && *s <= 'f') {
      r <<= 4;
      r += (*s - 'a') + 10;
    } else if (*s >= 'A' && *s <= 'F') {
      r <<= 4;
      r += (*s - 'A') + 10;
    } else {
      break;
    }
  }

  *result = r;
  return s;
}

const char* my_read_decimal_ptr(uintptr_t* result, const char* s) {
  uintptr_t r = 0;

  for (;; ++s) {
    if (*s >= '0' && *s <= '9') {
      r *= 10;
      r += *s - '0';
    } else {
      break;
    }
  }
  *result = r;
  return s;
}

void my_memset(void* ip, char c, size_t len) {
  char* p = (char *) ip;
  while (len--)
    *p++ = c;
}

size_t my_strlcpy(char* s1, const char* s2, size_t len) {
  size_t pos1 = 0;
  size_t pos2 = 0;

  while (s2[pos2] != '\0') {
    if (pos1 + 1 < len) {
      s1[pos1] = s2[pos2];
      pos1++;
    }
    pos2++;
  }
  if (len > 0)
    s1[pos1] = '\0';

  return pos2;
}

size_t my_strlcat(char* s1, const char* s2, size_t len) {
  size_t pos1 = 0;

  while (pos1 < len && s1[pos1] != '\0')
    pos1++;

  if (pos1 == len)
    return pos1;

  return pos1 + my_strlcpy(s1 + pos1, s2, len - pos1);
}

int my_isspace(int ch) {
  // Matches the C locale.
  const char spaces[] = " \t\f\n\r\t\v";
  for (size_t i = 0; i < sizeof(spaces); i++) {
    if (ch == spaces[i])
      return 1;
  }
  return 0;
}

}  // extern "C"
<commit_msg>Prepending file names with "src/" in #include directives is undesirable.<commit_after>// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. 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.

// This source file provides replacements for libc functions that we need. If
// we call the libc functions directly we risk crashing in the dynamic linker
// as it tries to resolve uncached PLT entries.

#include "common/linux/linux_libc_support.h"

#include <stddef.h>

extern "C" {

size_t my_strlen(const char* s) {
  size_t len = 0;
  while (*s++) len++;
  return len;
}

int my_strcmp(const char* a, const char* b) {
  for (;;) {
    if (*a < *b)
      return -1;
    else if (*a > *b)
      return 1;
    else if (*a == 0)
      return 0;
    a++;
    b++;
  }
}

int my_strncmp(const char* a, const char* b, size_t len) {
  for (size_t i = 0; i < len; ++i) {
    if (*a < *b)
      return -1;
    else if (*a > *b)
      return 1;
    else if (*a == 0)
      return 0;
    a++;
    b++;
  }

  return 0;
}

// Parse a non-negative integer.
//   result: (output) the resulting non-negative integer
//   s: a NUL terminated string
// Return true iff successful.
bool my_strtoui(int* result, const char* s) {
  if (*s == 0)
    return false;
  int r = 0;
  for (;; s++) {
    if (*s == 0)
      break;
    const int old_r = r;
    r *= 10;
    if (*s < '0' || *s > '9')
      return false;
    r += *s - '0';
    if (r < old_r)
      return false;
  }

  *result = r;
  return true;
}

// Return the length of the given, non-negative integer when expressed in base
// 10.
unsigned my_int_len(intmax_t i) {
  if (!i)
    return 1;

  int len = 0;
  while (i) {
    len++;
    i /= 10;
  }

  return len;
}

// Convert a non-negative integer to a string
//   output: (output) the resulting string is written here. This buffer must be
//     large enough to hold the resulting string. Call |my_int_len| to get the
//     required length.
//   i: the non-negative integer to serialise.
//   i_len: the length of the integer in base 10 (see |my_int_len|).
void my_itos(char* output, intmax_t i, unsigned i_len) {
  for (unsigned index = i_len; index; --index, i /= 10)
    output[index - 1] = '0' + (i % 10);
}

const char* my_strchr(const char* haystack, char needle) {
  while (*haystack && *haystack != needle)
    haystack++;
  if (*haystack == needle)
    return haystack;
  return (const char*) 0;
}

const char* my_strrchr(const char* haystack, char needle) {
  const char* ret = NULL;
  while (*haystack) {
    if (*haystack == needle)
      ret = haystack;
    haystack++;
  }
  return ret;
}

// Read a hex value
//   result: (output) the resulting value
//   s: a string
// Returns a pointer to the first invalid charactor.
const char* my_read_hex_ptr(uintptr_t* result, const char* s) {
  uintptr_t r = 0;

  for (;; ++s) {
    if (*s >= '0' && *s <= '9') {
      r <<= 4;
      r += *s - '0';
    } else if (*s >= 'a' && *s <= 'f') {
      r <<= 4;
      r += (*s - 'a') + 10;
    } else if (*s >= 'A' && *s <= 'F') {
      r <<= 4;
      r += (*s - 'A') + 10;
    } else {
      break;
    }
  }

  *result = r;
  return s;
}

const char* my_read_decimal_ptr(uintptr_t* result, const char* s) {
  uintptr_t r = 0;

  for (;; ++s) {
    if (*s >= '0' && *s <= '9') {
      r *= 10;
      r += *s - '0';
    } else {
      break;
    }
  }
  *result = r;
  return s;
}

void my_memset(void* ip, char c, size_t len) {
  char* p = (char *) ip;
  while (len--)
    *p++ = c;
}

size_t my_strlcpy(char* s1, const char* s2, size_t len) {
  size_t pos1 = 0;
  size_t pos2 = 0;

  while (s2[pos2] != '\0') {
    if (pos1 + 1 < len) {
      s1[pos1] = s2[pos2];
      pos1++;
    }
    pos2++;
  }
  if (len > 0)
    s1[pos1] = '\0';

  return pos2;
}

size_t my_strlcat(char* s1, const char* s2, size_t len) {
  size_t pos1 = 0;

  while (pos1 < len && s1[pos1] != '\0')
    pos1++;

  if (pos1 == len)
    return pos1;

  return pos1 + my_strlcpy(s1 + pos1, s2, len - pos1);
}

int my_isspace(int ch) {
  // Matches the C locale.
  const char spaces[] = " \t\f\n\r\t\v";
  for (size_t i = 0; i < sizeof(spaces); i++) {
    if (ch == spaces[i])
      return 1;
  }
  return 0;
}

}  // extern "C"
<|endoftext|>