<commit_before>/**************************************************************************
**
** Copyright (C) 2012, 2013 BlackBerry Limited. All rights reserved
**
** Contact: BlackBerry (qt@blackberry.com)
** Contact: KDAB (info@kdab.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 "qnxutils.h"
#include "qnxabstractqtversion.h"

#include <utils/hostosinfo.h>
#include <utils/synchronousprocess.h>

#include <QDir>
#include <QDesktopServices>
#include <QDomDocument>
#include <QProcess>
#include <QTemporaryFile>
#include <QApplication>

using namespace Qnx;
using namespace Qnx::Internal;

namespace {
const char *EVAL_ENV_VARS[] = {
    "QNX_TARGET", "QNX_HOST", "QNX_CONFIGURATION", "MAKEFLAGS", "LD_LIBRARY_PATH",
    "PATH", "QDE", "CPUVARDIR", "PYTHONPATH"
};
}

QString QnxUtils::addQuotes(const QString &string)
{
    return QLatin1Char('"') + string + QLatin1Char('"');
}

Qnx::QnxArchitecture QnxUtils::cpudirToArch(const QString &cpuDir)
{
    if (cpuDir == QLatin1String("x86"))
        return Qnx::X86;
    else if (cpuDir == QLatin1String("armle-v7"))
        return Qnx::ArmLeV7;
    else
        return Qnx::UnknownArch;
}

QStringList QnxUtils::searchPaths(QnxAbstractQtVersion *qtVersion)
{
    const QDir pluginDir(qtVersion->versionInfo().value(QLatin1String("QT_INSTALL_PLUGINS")));
    const QStringList pluginSubDirs = pluginDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);

    QStringList searchPaths;

    Q_FOREACH (const QString &dir, pluginSubDirs) {
        searchPaths << qtVersion->versionInfo().value(QLatin1String("QT_INSTALL_PLUGINS"))
                       + QLatin1Char('/') + dir;
    }

    searchPaths << qtVersion->versionInfo().value(QLatin1String("QT_INSTALL_LIBS"));
    searchPaths << qtVersion->qnxTarget() + QLatin1Char('/') + qtVersion->archString().toLower()
                   + QLatin1String("/lib");
    searchPaths << qtVersion->qnxTarget() + QLatin1Char('/') + qtVersion->archString().toLower()
                   + QLatin1String("/usr/lib");

    return searchPaths;
}

QList<Utils::EnvironmentItem> QnxUtils::qnxEnvironmentFromNdkFile(const QString &fileName)
{
    QList <Utils::EnvironmentItem> items;

    if (!QFileInfo(fileName).exists())
        return items;

    const bool isWindows = Utils::HostOsInfo::isWindowsHost();

    // locking creating bbndk-env file wrapper script
    QTemporaryFile tmpFile(
            QDir::tempPath() + QDir::separator()
            + QLatin1String("bbndk-env-eval-XXXXXX") + QLatin1String(isWindows ? ".bat" : ".sh"));
    if (!tmpFile.open())
        return items;
    tmpFile.setTextModeEnabled(true);

    // writing content to wrapper script
    QTextStream fileContent(&tmpFile);
    if (isWindows)
        fileContent << QLatin1String("@echo off\n")
                    << QLatin1String("call ") << fileName << QLatin1Char('\n');
    else
        fileContent << QLatin1String("#!/bin/bash\n")
                    << QLatin1String(". ") << fileName << QLatin1Char('\n');
    QString linePattern = QString::fromLatin1(isWindows ? "echo %1=%%1%" : "echo %1=$%1");
    for (int i = 0, len = sizeof(EVAL_ENV_VARS) / sizeof(const char *); i < len; ++i)
        fileContent << linePattern.arg(QLatin1String(EVAL_ENV_VARS[i])) << QLatin1Char('\n');
    tmpFile.close();

    // running wrapper script
    QProcess process;
    if (isWindows)
        process.start(QLatin1String("cmd.exe"),
                QStringList() << QLatin1String("/C") << tmpFile.fileName());
    else
        process.start(QLatin1String("/bin/bash"),
                QStringList() << tmpFile.fileName());

    // waiting for finish
    QApplication::setOverrideCursor(Qt::BusyCursor);
    bool waitResult = process.waitForFinished(10000);
    QApplication::restoreOverrideCursor();
    if (!waitResult) {
        Utils::SynchronousProcess::stopProcess(process);
        return items;
    }

    if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0)
        return items;

    // parsing process output
    QTextStream str(&process);
    while (!str.atEnd()) {
        QString line = str.readLine();
        int equalIndex = line.indexOf(QLatin1Char('='));
        if (equalIndex < 0)
            continue;
        QString var = line.left(equalIndex);
        QString value = line.mid(equalIndex + 1);
        items.append(Utils::EnvironmentItem(var, value));
    }

    return items;
}

bool QnxUtils::isValidNdkPath(const QString &ndkPath)
{
    return (QFileInfo(envFilePath(ndkPath)).exists());
}

QString QnxUtils::envFilePath(const QString &ndkPath, const QString &targetVersion)
{
    QString envFile;
    if (Utils::HostOsInfo::isWindowsHost())
        envFile = ndkPath + QLatin1String("/bbndk-env.bat");
    else if (Utils::HostOsInfo::isAnyUnixHost())
        envFile = ndkPath + QLatin1String("/bbndk-env.sh");

    if (!QFileInfo(envFile).exists()) {
        QString version = targetVersion.isEmpty() ? defaultTargetVersion(ndkPath) : targetVersion;
        version = version.replace(QLatin1Char('.'), QLatin1Char('_'));
        if (Utils::HostOsInfo::isWindowsHost())
            envFile = ndkPath + QLatin1String("/bbndk-env_") + version + QLatin1String(".bat");
        else if (Utils::HostOsInfo::isAnyUnixHost())
            envFile = ndkPath + QLatin1String("/bbndk-env_") + version + QLatin1String(".sh");
    }
    return envFile;
}

Utils::FileName QnxUtils::executableWithExtension(const Utils::FileName &fileName)
{
    Utils::FileName result = fileName;
    if (Utils::HostOsInfo::isWindowsHost())
        result.append(QLatin1String(".exe"));
    return result;
}

QString QnxUtils::dataDirPath()
{
    const QString homeDir = QDir::homePath();

    if (Utils::HostOsInfo::isMacHost())
        return homeDir + QLatin1String("/Library/Research in Motion");

    if (Utils::HostOsInfo::isAnyUnixHost())
        return homeDir + QLatin1String("/.rim");

    if (Utils::HostOsInfo::isWindowsHost()) {
        // Get the proper storage location on Windows using QDesktopServices,
        // to not hardcode "AppData/Local", as it might refer to "AppData/Roaming".
        QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
        dataDir = dataDir.left(dataDir.indexOf(QCoreApplication::organizationName()));
        dataDir.append(QLatin1String("Research in Motion"));
        return dataDir;
    }

    return QString();
}

QString QnxUtils::qConfigPath()
{
    if (Utils::HostOsInfo::isMacHost() || Utils::HostOsInfo::isWindowsHost())
        return dataDirPath() + QLatin1String("/BlackBerry Native SDK/qconfig");
    else
        return dataDirPath() + QLatin1String("/bbndk/qconfig");
}

QString QnxUtils::defaultTargetVersion(const QString &ndkPath)
{
    foreach (const NdkInstallInformation &ndkInfo, installedNdks()) {
        if (!ndkInfo.path.compare(ndkPath, Utils::HostOsInfo::fileNameCaseSensitivity()))
            return ndkInfo.version;
    }

    return QString();
}

QList<NdkInstallInformation> QnxUtils::installedNdks()
{
    QList<NdkInstallInformation> ndkList;
    QString ndkConfigPath = qConfigPath();
    if (!QDir(ndkConfigPath).exists())
        return ndkList;

    QFileInfoList ndkfileList = QDir(ndkConfigPath).entryInfoList(QStringList() << QLatin1String("*.xml"),
                                                                  QDir::Files, QDir::Time);
    foreach (const QFileInfo &ndkFile, ndkfileList) {
        QFile xmlFile(ndkFile.absoluteFilePath());
        if (!xmlFile.open(QIODevice::ReadOnly))
            continue;

        QDomDocument doc;
        if (!doc.setContent(&xmlFile))  // Skip error message
            continue;

        QDomElement docElt = doc.documentElement();
        if (docElt.tagName() != QLatin1String("qnxSystemDefinition"))
            continue;

        QDomElement childElt = docElt.firstChildElement(QLatin1String("installation"));
        // The file contains only one installation node
        if (!childElt.isNull()) {
            // The file contains only one base node
            NdkInstallInformation ndkInfo;
            ndkInfo.path = childElt.firstChildElement(QLatin1String("base")).text();
            ndkInfo.name = childElt.firstChildElement(QLatin1String("name")).text();
            ndkInfo.host = childElt.firstChildElement(QLatin1String("host")).text();
            ndkInfo.target = childElt.firstChildElement(QLatin1String("target")).text();
            ndkInfo.version = childElt.firstChildElement(QLatin1String("version")).text();

            ndkList.append(ndkInfo);
        }
    }

    return ndkList;
}

QString QnxUtils::sdkInstallerPath(const QString &ndkPath)
{
    QString sdkinstallPath;
    if (Utils::HostOsInfo::isWindowsHost())
        sdkinstallPath = ndkPath + QLatin1String("/qde.exe");
    else
        sdkinstallPath = ndkPath + QLatin1String("/qde");

    if (QFileInfo(sdkinstallPath).exists())
        return sdkinstallPath;

    return QString();
}

// The resulting process when launching sdkinstall
QString QnxUtils::qdeInstallProcess(const QString &ndkPath, const QString &option, const QString &version)
{
    QString installerPath = sdkInstallerPath(ndkPath);
    if (installerPath.isEmpty())
        return QString();

    return QString::fromLatin1("%1 -nosplash -application com.qnx.tools.ide.sdk.manager.core.SDKInstallerApplication "
                               "%2  %3 -vmargs -Dosgi.console=:none").arg(installerPath, option, version);
}

QList<Utils::EnvironmentItem> QnxUtils::qnxEnvironment(const QString &sdkPath)
{
    // Mimic what the SDP installer puts into the system environment

    QList<Utils::EnvironmentItem> environmentItems;

    if (Utils::HostOsInfo::isWindowsHost()) {
        // TODO:
        //environment.insert(QLatin1String("QNX_CONFIGURATION"), QLatin1String("/etc/qnx"));
        environmentItems.append(Utils::EnvironmentItem(QLatin1String(Constants::QNX_TARGET_KEY), sdkPath + QLatin1String("/target/qnx6")));
        environmentItems.append(Utils::EnvironmentItem(QLatin1String(Constants::QNX_HOST_KEY), sdkPath + QLatin1String("/host/win32/x86")));

        environmentItems.append(Utils::EnvironmentItem(QLatin1String("PATH"), sdkPath + QLatin1String("/host/win32/x86/usr/bin;%PATH%")));

        // TODO:
        //environment.insert(QLatin1String("PATH"), QLatin1String("/etc/qnx/bin"));
    } else if (Utils::HostOsInfo::isAnyUnixHost()) {
        environmentItems.append(Utils::EnvironmentItem(QLatin1String("QNX_CONFIGURATION"), QLatin1String("/etc/qnx")));
        environmentItems.append(Utils::EnvironmentItem(QLatin1String(Constants::QNX_TARGET_KEY), sdkPath + QLatin1String("/target/qnx6")));
        environmentItems.append(Utils::EnvironmentItem(QLatin1String(Constants::QNX_HOST_KEY), sdkPath + QLatin1String("/host/linux/x86")));

        environmentItems.append(Utils::EnvironmentItem(QLatin1String("PATH"), sdkPath + QLatin1String("/host/linux/x86/usr/bin:/etc/qnx/bin:${PATH}")));

        environmentItems.append(Utils::EnvironmentItem(QLatin1String("LD_LIBRARY_PATH"), sdkPath + QLatin1String("/host/linux/x86/usr/lib:${LD_LIBRARY_PATH}")));
    }

    environmentItems.append(Utils::EnvironmentItem(QLatin1String("QNX_JAVAHOME"), sdkPath + QLatin1String("/_jvm")));
    environmentItems.append(Utils::EnvironmentItem(QLatin1String("MAKEFLAGS"), QLatin1String("-I") + sdkPath + QLatin1String("/target/qnx6/usr/include")));

    return environmentItems;
}
<commit_msg>QNX: Use correct command for running the SDK installer<commit_after>/**************************************************************************
**
** Copyright (C) 2012, 2013 BlackBerry Limited. All rights reserved
**
** Contact: BlackBerry (qt@blackberry.com)
** Contact: KDAB (info@kdab.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 "qnxutils.h"
#include "qnxabstractqtversion.h"

#include <utils/hostosinfo.h>
#include <utils/synchronousprocess.h>

#include <QDir>
#include <QDesktopServices>
#include <QDomDocument>
#include <QProcess>
#include <QTemporaryFile>
#include <QApplication>

using namespace Qnx;
using namespace Qnx::Internal;

namespace {
const char *EVAL_ENV_VARS[] = {
    "QNX_TARGET", "QNX_HOST", "QNX_CONFIGURATION", "MAKEFLAGS", "LD_LIBRARY_PATH",
    "PATH", "QDE", "CPUVARDIR", "PYTHONPATH"
};
}

QString QnxUtils::addQuotes(const QString &string)
{
    return QLatin1Char('"') + string + QLatin1Char('"');
}

Qnx::QnxArchitecture QnxUtils::cpudirToArch(const QString &cpuDir)
{
    if (cpuDir == QLatin1String("x86"))
        return Qnx::X86;
    else if (cpuDir == QLatin1String("armle-v7"))
        return Qnx::ArmLeV7;
    else
        return Qnx::UnknownArch;
}

QStringList QnxUtils::searchPaths(QnxAbstractQtVersion *qtVersion)
{
    const QDir pluginDir(qtVersion->versionInfo().value(QLatin1String("QT_INSTALL_PLUGINS")));
    const QStringList pluginSubDirs = pluginDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);

    QStringList searchPaths;

    Q_FOREACH (const QString &dir, pluginSubDirs) {
        searchPaths << qtVersion->versionInfo().value(QLatin1String("QT_INSTALL_PLUGINS"))
                       + QLatin1Char('/') + dir;
    }

    searchPaths << qtVersion->versionInfo().value(QLatin1String("QT_INSTALL_LIBS"));
    searchPaths << qtVersion->qnxTarget() + QLatin1Char('/') + qtVersion->archString().toLower()
                   + QLatin1String("/lib");
    searchPaths << qtVersion->qnxTarget() + QLatin1Char('/') + qtVersion->archString().toLower()
                   + QLatin1String("/usr/lib");

    return searchPaths;
}

QList<Utils::EnvironmentItem> QnxUtils::qnxEnvironmentFromNdkFile(const QString &fileName)
{
    QList <Utils::EnvironmentItem> items;

    if (!QFileInfo(fileName).exists())
        return items;

    const bool isWindows = Utils::HostOsInfo::isWindowsHost();

    // locking creating bbndk-env file wrapper script
    QTemporaryFile tmpFile(
            QDir::tempPath() + QDir::separator()
            + QLatin1String("bbndk-env-eval-XXXXXX") + QLatin1String(isWindows ? ".bat" : ".sh"));
    if (!tmpFile.open())
        return items;
    tmpFile.setTextModeEnabled(true);

    // writing content to wrapper script
    QTextStream fileContent(&tmpFile);
    if (isWindows)
        fileContent << QLatin1String("@echo off\n")
                    << QLatin1String("call ") << fileName << QLatin1Char('\n');
    else
        fileContent << QLatin1String("#!/bin/bash\n")
                    << QLatin1String(". ") << fileName << QLatin1Char('\n');
    QString linePattern = QString::fromLatin1(isWindows ? "echo %1=%%1%" : "echo %1=$%1");
    for (int i = 0, len = sizeof(EVAL_ENV_VARS) / sizeof(const char *); i < len; ++i)
        fileContent << linePattern.arg(QLatin1String(EVAL_ENV_VARS[i])) << QLatin1Char('\n');
    tmpFile.close();

    // running wrapper script
    QProcess process;
    if (isWindows)
        process.start(QLatin1String("cmd.exe"),
                QStringList() << QLatin1String("/C") << tmpFile.fileName());
    else
        process.start(QLatin1String("/bin/bash"),
                QStringList() << tmpFile.fileName());

    // waiting for finish
    QApplication::setOverrideCursor(Qt::BusyCursor);
    bool waitResult = process.waitForFinished(10000);
    QApplication::restoreOverrideCursor();
    if (!waitResult) {
        Utils::SynchronousProcess::stopProcess(process);
        return items;
    }

    if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0)
        return items;

    // parsing process output
    QTextStream str(&process);
    while (!str.atEnd()) {
        QString line = str.readLine();
        int equalIndex = line.indexOf(QLatin1Char('='));
        if (equalIndex < 0)
            continue;
        QString var = line.left(equalIndex);
        QString value = line.mid(equalIndex + 1);
        items.append(Utils::EnvironmentItem(var, value));
    }

    return items;
}

bool QnxUtils::isValidNdkPath(const QString &ndkPath)
{
    return (QFileInfo(envFilePath(ndkPath)).exists());
}

QString QnxUtils::envFilePath(const QString &ndkPath, const QString &targetVersion)
{
    QString envFile;
    if (Utils::HostOsInfo::isWindowsHost())
        envFile = ndkPath + QLatin1String("/bbndk-env.bat");
    else if (Utils::HostOsInfo::isAnyUnixHost())
        envFile = ndkPath + QLatin1String("/bbndk-env.sh");

    if (!QFileInfo(envFile).exists()) {
        QString version = targetVersion.isEmpty() ? defaultTargetVersion(ndkPath) : targetVersion;
        version = version.replace(QLatin1Char('.'), QLatin1Char('_'));
        if (Utils::HostOsInfo::isWindowsHost())
            envFile = ndkPath + QLatin1String("/bbndk-env_") + version + QLatin1String(".bat");
        else if (Utils::HostOsInfo::isAnyUnixHost())
            envFile = ndkPath + QLatin1String("/bbndk-env_") + version + QLatin1String(".sh");
    }
    return envFile;
}

Utils::FileName QnxUtils::executableWithExtension(const Utils::FileName &fileName)
{
    Utils::FileName result = fileName;
    if (Utils::HostOsInfo::isWindowsHost())
        result.append(QLatin1String(".exe"));
    return result;
}

QString QnxUtils::dataDirPath()
{
    const QString homeDir = QDir::homePath();

    if (Utils::HostOsInfo::isMacHost())
        return homeDir + QLatin1String("/Library/Research in Motion");

    if (Utils::HostOsInfo::isAnyUnixHost())
        return homeDir + QLatin1String("/.rim");

    if (Utils::HostOsInfo::isWindowsHost()) {
        // Get the proper storage location on Windows using QDesktopServices,
        // to not hardcode "AppData/Local", as it might refer to "AppData/Roaming".
        QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
        dataDir = dataDir.left(dataDir.indexOf(QCoreApplication::organizationName()));
        dataDir.append(QLatin1String("Research in Motion"));
        return dataDir;
    }

    return QString();
}

QString QnxUtils::qConfigPath()
{
    if (Utils::HostOsInfo::isMacHost() || Utils::HostOsInfo::isWindowsHost())
        return dataDirPath() + QLatin1String("/BlackBerry Native SDK/qconfig");
    else
        return dataDirPath() + QLatin1String("/bbndk/qconfig");
}

QString QnxUtils::defaultTargetVersion(const QString &ndkPath)
{
    foreach (const NdkInstallInformation &ndkInfo, installedNdks()) {
        if (!ndkInfo.path.compare(ndkPath, Utils::HostOsInfo::fileNameCaseSensitivity()))
            return ndkInfo.version;
    }

    return QString();
}

QList<NdkInstallInformation> QnxUtils::installedNdks()
{
    QList<NdkInstallInformation> ndkList;
    QString ndkConfigPath = qConfigPath();
    if (!QDir(ndkConfigPath).exists())
        return ndkList;

    QFileInfoList ndkfileList = QDir(ndkConfigPath).entryInfoList(QStringList() << QLatin1String("*.xml"),
                                                                  QDir::Files, QDir::Time);
    foreach (const QFileInfo &ndkFile, ndkfileList) {
        QFile xmlFile(ndkFile.absoluteFilePath());
        if (!xmlFile.open(QIODevice::ReadOnly))
            continue;

        QDomDocument doc;
        if (!doc.setContent(&xmlFile))  // Skip error message
            continue;

        QDomElement docElt = doc.documentElement();
        if (docElt.tagName() != QLatin1String("qnxSystemDefinition"))
            continue;

        QDomElement childElt = docElt.firstChildElement(QLatin1String("installation"));
        // The file contains only one installation node
        if (!childElt.isNull()) {
            // The file contains only one base node
            NdkInstallInformation ndkInfo;
            ndkInfo.path = childElt.firstChildElement(QLatin1String("base")).text();
            ndkInfo.name = childElt.firstChildElement(QLatin1String("name")).text();
            ndkInfo.host = childElt.firstChildElement(QLatin1String("host")).text();
            ndkInfo.target = childElt.firstChildElement(QLatin1String("target")).text();
            ndkInfo.version = childElt.firstChildElement(QLatin1String("version")).text();

            ndkList.append(ndkInfo);
        }
    }

    return ndkList;
}

QString QnxUtils::sdkInstallerPath(const QString &ndkPath)
{
    QString sdkinstallPath;
    if (Utils::HostOsInfo::isWindowsHost())
        sdkinstallPath = ndkPath + QLatin1String("/qde.exe");
    else
        sdkinstallPath = ndkPath + QLatin1String("/qde");

    if (QFileInfo(sdkinstallPath).exists())
        return sdkinstallPath;

    return QString();
}

// The resulting process when launching sdkinstall
QString QnxUtils::qdeInstallProcess(const QString &ndkPath, const QString &option, const QString &version)
{
    QString installerPath = sdkInstallerPath(ndkPath);
    if (installerPath.isEmpty())
        return QString();

    const QDir pluginDir(ndkPath + QLatin1String("/plugins"));
    const QStringList installerPlugins = pluginDir.entryList(QStringList() << QLatin1String("com.qnx.tools.ide.sdk.installer.app_*.jar"));
    const QString installerApplication = installerPlugins.size() >= 1 ? QLatin1String("com.qnx.tools.ide.sdk.installer.app.SDKInstallerApplication")
                                                                      : QLatin1String("com.qnx.tools.ide.sdk.manager.core.SDKInstallerApplication");
    return QString::fromLatin1("%1 -nosplash -application %2 "
                               "%3  %4 -vmargs -Dosgi.console=:none").arg(installerPath, installerApplication, option, version);
}

QList<Utils::EnvironmentItem> QnxUtils::qnxEnvironment(const QString &sdkPath)
{
    // Mimic what the SDP installer puts into the system environment

    QList<Utils::EnvironmentItem> environmentItems;

    if (Utils::HostOsInfo::isWindowsHost()) {
        // TODO:
        //environment.insert(QLatin1String("QNX_CONFIGURATION"), QLatin1String("/etc/qnx"));
        environmentItems.append(Utils::EnvironmentItem(QLatin1String(Constants::QNX_TARGET_KEY), sdkPath + QLatin1String("/target/qnx6")));
        environmentItems.append(Utils::EnvironmentItem(QLatin1String(Constants::QNX_HOST_KEY), sdkPath + QLatin1String("/host/win32/x86")));

        environmentItems.append(Utils::EnvironmentItem(QLatin1String("PATH"), sdkPath + QLatin1String("/host/win32/x86/usr/bin;%PATH%")));

        // TODO:
        //environment.insert(QLatin1String("PATH"), QLatin1String("/etc/qnx/bin"));
    } else if (Utils::HostOsInfo::isAnyUnixHost()) {
        environmentItems.append(Utils::EnvironmentItem(QLatin1String("QNX_CONFIGURATION"), QLatin1String("/etc/qnx")));
        environmentItems.append(Utils::EnvironmentItem(QLatin1String(Constants::QNX_TARGET_KEY), sdkPath + QLatin1String("/target/qnx6")));
        environmentItems.append(Utils::EnvironmentItem(QLatin1String(Constants::QNX_HOST_KEY), sdkPath + QLatin1String("/host/linux/x86")));

        environmentItems.append(Utils::EnvironmentItem(QLatin1String("PATH"), sdkPath + QLatin1String("/host/linux/x86/usr/bin:/etc/qnx/bin:${PATH}")));

        environmentItems.append(Utils::EnvironmentItem(QLatin1String("LD_LIBRARY_PATH"), sdkPath + QLatin1String("/host/linux/x86/usr/lib:${LD_LIBRARY_PATH}")));
    }

    environmentItems.append(Utils::EnvironmentItem(QLatin1String("QNX_JAVAHOME"), sdkPath + QLatin1String("/_jvm")));
    environmentItems.append(Utils::EnvironmentItem(QLatin1String("MAKEFLAGS"), QLatin1String("-I") + sdkPath + QLatin1String("/target/qnx6/usr/include")));

    return environmentItems;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include<iostream>
#include<thread>

#include<cstdio>
#include<cstring>

#include<sys/socket.h>
#include<sys/un.h>
#include<sys/types.h>
#include<unistd.h>
#include<signal.h>

#include <wiringPi.h>

namespace {

int socket_fd;

const std::size_t UNIX_PATH_MAX = 108;
const std::size_t gpio_led_pin = 1;

char buffer[4096];

void connection_handler(int connection_fd){
    std::cout << "asgard: New connection received" << std::endl;

    int nbytes;
    while((nbytes = read(connection_fd, buffer, 4096)) > 0){
        buffer[nbytes] = 0;
        std::cout << "asgard: Received message: " << buffer << std::endl;
    }

    close(connection_fd);
}

void close(){
    digitalWrite(gpio_led_pin, LOW);

    close(socket_fd);
    unlink("/tmp/asgard_socket");
}

void terminate(int /*signo*/){
    close();

    abort();
}

bool revoke_root(){
    if (getuid() == 0) {
        if (setgid(1000) != 0){
            std::cout << "asgard: setgid: Unable to drop group privileges: " << strerror(errno) << std::endl;
            return false;
        }

        if (setuid(1000) != 0){
            std::cout << "asgard: setgid: Unable to drop user privileges: " << strerror(errno) << std::endl;
            return false;
        }
    }

    if (setuid(0) != -1){
        std::cout << "asgard: managed to regain root privileges, exiting..." << std::endl;
        return false;
    }

    return true;
}

} //end of anonymous namespace

int main(){
    //Run the wiringPi setup (as root)
    wiringPiSetup();

    //Drop root privileges and run as pi:pi again
    if(!revoke_root()){
       std::cout << "asgard: unable to revoke root privileges, exiting..." << std::endl;
       return 1;
    }

    //Register signals for "proper" shutdown
    signal(SIGTERM, terminate);
    signal(SIGINT, terminate);

    pinMode(gpio_led_pin, OUTPUT);
    digitalWrite(gpio_led_pin, HIGH);

    //Open the socket
    socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
    if(socket_fd < 0){
        printf("socket() failed\n");
        return 1;
    }

    unlink("/tmp/asgard_socket");

    //Init the address
    struct sockaddr_un address;
    memset(&address, 0, sizeof(struct sockaddr_un));
    address.sun_family = AF_UNIX;
    snprintf(address.sun_path, UNIX_PATH_MAX, "/tmp/asgard_socket");

    //Bind
    if(bind(socket_fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0){
        printf("bind() failed\n");
        return 1;
    }

    if(listen(socket_fd, 5) != 0){
        printf("listen() failed\n");
        return 1;
    }

    int connection_fd;
    socklen_t address_length;
    while((connection_fd = accept(socket_fd, (struct sockaddr *) &address, &address_length)) > -1){
        std::thread(connection_handler, connection_fd).detach();
    }

    close();

    return 0;
}
<commit_msg>Fix buffer<commit_after>//=======================================================================
// Copyright (c) 2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include<iostream>
#include<thread>

#include<cstdio>
#include<cstring>

#include<sys/socket.h>
#include<sys/un.h>
#include<sys/types.h>
#include<unistd.h>
#include<signal.h>

#include <wiringPi.h>

namespace {

int socket_fd;

const std::size_t UNIX_PATH_MAX = 108;
const std::size_t gpio_led_pin = 1;
const std::size_t socket_buffer_size = 4096;

void connection_handler(int connection_fd){
    char buffer[socket_buffer_size];

    std::cout << "asgard: New connection received" << std::endl;

    int nbytes;
    while((nbytes = read(connection_fd, buffer, socket_buffer_size)) > 0){
        buffer[nbytes] = 0;
        std::cout << "asgard: Received message: " << buffer << std::endl;

    }

    close(connection_fd);
}

void close(){
    digitalWrite(gpio_led_pin, LOW);

    close(socket_fd);
    unlink("/tmp/asgard_socket");
}

void terminate(int /*signo*/){
    close();

    abort();
}

bool revoke_root(){
    if (getuid() == 0) {
        if (setgid(1000) != 0){
            std::cout << "asgard: setgid: Unable to drop group privileges: " << strerror(errno) << std::endl;
            return false;
        }

        if (setuid(1000) != 0){
            std::cout << "asgard: setgid: Unable to drop user privileges: " << strerror(errno) << std::endl;
            return false;
        }
    }

    if (setuid(0) != -1){
        std::cout << "asgard: managed to regain root privileges, exiting..." << std::endl;
        return false;
    }

    return true;
}

} //end of anonymous namespace

int main(){
    //Run the wiringPi setup (as root)
    wiringPiSetup();

    //Drop root privileges and run as pi:pi again
    if(!revoke_root()){
       std::cout << "asgard: unable to revoke root privileges, exiting..." << std::endl;
       return 1;
    }

    //Register signals for "proper" shutdown
    signal(SIGTERM, terminate);
    signal(SIGINT, terminate);

    pinMode(gpio_led_pin, OUTPUT);
    digitalWrite(gpio_led_pin, HIGH);

    //Open the socket
    socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
    if(socket_fd < 0){
        printf("socket() failed\n");
        return 1;
    }

    unlink("/tmp/asgard_socket");

    //Init the address
    struct sockaddr_un address;
    memset(&address, 0, sizeof(struct sockaddr_un));
    address.sun_family = AF_UNIX;
    snprintf(address.sun_path, UNIX_PATH_MAX, "/tmp/asgard_socket");

    //Bind
    if(bind(socket_fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0){
        printf("bind() failed\n");
        return 1;
    }

    if(listen(socket_fd, 5) != 0){
        printf("listen() failed\n");
        return 1;
    }

    int connection_fd;
    socklen_t address_length;
    while((connection_fd = accept(socket_fd, (struct sockaddr *) &address, &address_length)) > -1){
        std::thread(connection_handler, connection_fd).detach();
    }

    close();

    return 0;
}
<|endoftext|>


<commit_before>/*
 * ============================================================================
 *       Filename:  server.hxx
 *    Description:  Server side implementation for flihabi network
 *        Version:  1.0
 *        Created:  04/20/2015 06:21:00 PM
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:  Rafael Gozlan
 *   Organization:  Flihabi
 * ============================================================================
 */

#include <thread>
#include <iostream>

#include "server.hh"
#include "broadcaster.hh"
#include "listener.hh"
#include "network.hh"

// PUBLIC METHODS

Server::Server(int port) : results_(), busy_(), todo_()
{
    port_ = port;
    // Launch the server broadcaster and connection handler
    std::thread broadcaster(broadcastLoop);
    broadcaster.detach();
    std::thread handler(Server::handler);
    handler.detach();
}

Result *Server::getResult(int i)
{
    Result *r = results_[i];
    if (r != NULL)
    {
        results_[i] = NULL;
        busy_[i] = false;   /* set busy to false so the emplacement is free*/
    }
    return r;
}

// PRIVATE METHODS

void Server::setResult(int i, std::string s)
{
    Result *r = new Result();
    /* TODO: Test if s is persistant */
    r->value = s;
    results_[i] = r;
}

int Server::getResultEmplacement()
{
    for (size_t i = 0; i < busy_.size(); i++)
    {
        if (!busy_[i])
        {
            busy_[i] = true;
            return i;
        }
    }
    /* Add emplacement */
    busy_.push_back(false);
    results_.push_back(NULL);
    return getResultEmplacement(); /* FIXME: not optimal */
}

/* Server slaves handling */
void Server::handler()
{
    int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
    struct addrinfo hints, *servinfo, *p;
    struct sockaddr_storage their_addr; // connector's address information
    socklen_t sin_size;
    int yes=1;
    char s[INET6_ADDRSTRLEN];
    int rv;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; // use my IP

    if ((rv = getaddrinfo(NULL, std::to_string(CONNECTION_PORT).c_str(),
                                &hints, &servinfo)) != 0)
    {
        fprintf(stderr, "Handler: getaddrinfo: %s\n", gai_strerror(rv));
        return;
    }

    // loop through all the results and bind to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("Handler: socket");
            continue;
        }

        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                sizeof(int)) == -1) {
            perror("Handler: setsockopt");
            exit(1);
        }

        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("Handler: bind");
            continue;
        }

        break;
    }

    if (p == NULL)  {
        fprintf(stderr, "Handler: failed to bind\n");
        return;
    }

    freeaddrinfo(servinfo); // all done with this structure

    if (listen(sockfd, 10) == -1)
    {
        perror("listen");
        exit(1);
    }

    printf("Handler: waiting for connections...\n");

    while (true) /* I love stuff like this */
    {
        sin_size = sizeof their_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
        if (new_fd == -1) {
            perror("Handler: accept");
            continue;
        }

        inet_ntop(their_addr.ss_family,
            get_in_addr((struct sockaddr *)&their_addr),
            s, sizeof s);
        printf("Handler: got connection from %s\n", s);

        std::thread client(clientThread, new_fd);
    }
}

void Server::clientThread(int s)
{
    std::cout << "Client thread: Hello!" << std::endl;
    if (s)
        return;
}
<commit_msg>Server: sending ack after slave connection<commit_after>/*
 * ============================================================================
 *       Filename:  server.hxx
 *    Description:  Server side implementation for flihabi network
 *        Version:  1.0
 *        Created:  04/20/2015 06:21:00 PM
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:  Rafael Gozlan
 *   Organization:  Flihabi
 * ============================================================================
 */

#include <thread>
#include <iostream>

#include "server.hh"
#include "broadcaster.hh"
#include "listener.hh"
#include "network.hh"

// PUBLIC METHODS

Server::Server(int port) : results_(), busy_(), todo_()
{
    port_ = port;
    // Launch the server broadcaster and connection handler
    std::thread broadcaster(broadcastLoop);
    broadcaster.detach();
    std::thread handler(Server::handler);
    handler.detach();
}

Result *Server::getResult(int i)
{
    Result *r = results_[i];
    if (r != NULL)
    {
        results_[i] = NULL;
        busy_[i] = false;   /* set busy to false so the emplacement is free*/
    }
    return r;
}

// PRIVATE METHODS

void Server::setResult(int i, std::string s)
{
    Result *r = new Result();
    /* TODO: Test if s is persistant */
    r->value = s;
    results_[i] = r;
}

int Server::getResultEmplacement()
{
    for (size_t i = 0; i < busy_.size(); i++)
    {
        if (!busy_[i])
        {
            busy_[i] = true;
            return i;
        }
    }
    /* Add emplacement */
    busy_.push_back(false);
    results_.push_back(NULL);
    return getResultEmplacement(); /* FIXME: not optimal */
}

/* Server slaves handling */
void Server::handler()
{
    int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
    struct addrinfo hints, *servinfo, *p;
    struct sockaddr_storage their_addr; // connector's address information
    socklen_t sin_size;
    int yes=1;
    char s[INET6_ADDRSTRLEN];
    int rv;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; // use my IP

    if ((rv = getaddrinfo(NULL, std::to_string(CONNECTION_PORT).c_str(),
                                &hints, &servinfo)) != 0)
    {
        fprintf(stderr, "Handler: getaddrinfo: %s\n", gai_strerror(rv));
        return;
    }

    // loop through all the results and bind to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("Handler: socket");
            continue;
        }

        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                sizeof(int)) == -1) {
            perror("Handler: setsockopt");
            exit(1);
        }

        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("Handler: bind");
            continue;
        }

        break;
    }

    if (p == NULL)  {
        fprintf(stderr, "Handler: failed to bind\n");
        return;
    }

    freeaddrinfo(servinfo); // all done with this structure

    if (listen(sockfd, 10) == -1)
    {
        perror("listen");
        exit(1);
    }

    printf("Handler: waiting for connections...\n");

    while (true) /* I love stuff like this */
    {
        sin_size = sizeof their_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
        if (new_fd == -1) {
            perror("Handler: accept");
            continue;
        }

        inet_ntop(their_addr.ss_family,
            get_in_addr((struct sockaddr *)&their_addr),
            s, sizeof s);
        printf("Handler: got connection from %s\n", s);

        int numbytes;
        char buf[100];
        // Receiving connection msg
        if ((numbytes = recv(sockfd, buf, 100-1, 0)) == -1)
        {
            perror("Server: failed to recv the connection msg");
            exit(1);
        }
        buf[numbytes] = '\0';
        printf("Server: received '%s'\n",buf);
        if (std::string(buf) == CONNECTION_MSG)
        {
            std::thread client(clientThread, new_fd);
            client.detach();
        }
    }
}

void Server::clientThread(int sockfd)
{
    std::cout << "Client thread: sending Hello!" << std::endl;
    // Sending ACK
    if (send(sockfd, CONNECTION_MSG, strlen(CONNECTION_MSG), 0) == -1)
        perror("Server: failed sending Hello!");
    // Receiving ACK
}
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief Read key sets using yaml-cpp
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include "read.hpp"
#include "yaml-cpp/yaml.h"

#include <kdb.hpp>
#include <kdbease.h>
#include <kdblogger.h>
#include <kdbplugin.h>

#include <sstream>

using namespace std;
using namespace kdb;

namespace
{
/**
 * @brief This function creates a new key from the given parameters.
 *
 * @param name This string specifies the postfix of the name of the key produced by this function.
 * @param parent This key specifies the prefix of the name of the key produced by this function.
 *
 * @returns The function returns a new key that combines the name of the parent key and `name`.
 */
Key newKey (string const & name, Key const & parent)
{
	ELEKTRA_LOG_DEBUG ("Add new key with base name “%s”", name.c_str ());

	Key key{ parent.getFullName (), KEY_BINARY, KEY_END };
	key.addBaseName (name);

	return key;
}

/**
 * @brief This function creates a new array key from the given parameters.
 *
 * @param mappings This argument specifies the key set of the new key this function creates.
 * @param arrayKey This argument specifies the key that represents the root of the array.
 *
 * @returns The function returns a new key that is part of the array represented by `arrayKey`.
 */
Key newArrayKey (KeySet const & mappings, Key & arrayKey)
{
	ELEKTRA_LOG_DEBUG ("Add new array element to array parent “%s”", arrayKey.getName ().c_str ());

	KeySet arrayEntries{ elektraArrayGet (*arrayKey, mappings.getKeySet ()) };

	if (arrayEntries.size () <= 0)
	{
		Key first = arrayKey.dup ();
		first.addBaseName ("#");
		arrayEntries.append (first);
	}

	Key newKey{ elektraArrayGetNextKey (arrayEntries.getKeySet ()) };
	arrayKey.setMeta ("array", newKey.getBaseName ());

	return newKey;
}

/**
 * @brief Add metadata saved in a YAML map to the specified key
 *
 * @param key This parameter saves the key to which this function should add the metadata stored in `node`.
 * @param node This YAML node stores a map containing metadata.
 */
void addMetadata (Key & key, YAML::Node const & node)
{
	for (auto & element : node)
	{
		auto metakey = element.first.as<string> ();
		auto metavalue = element.second.IsNull () ? "" : element.second.as<string> ();
		ELEKTRA_LOG_DEBUG ("Add metakey “%s: %s”", metakey.c_str (), metavalue.c_str ());
		key.setMeta (metakey, metavalue);
	}
}

/**
 * @brief Create a key containing a (possibly empty) value.
 *
 * @param node This YAML node stores the data that should be converted to a new `Key`.
 * @param name This text specifies the name of the key this function creates.
 *
 * @return A new key containing the data specified in `node`
 */
Key createLeafKey (YAML::Node const & node, string const & name)
{
	Key key{ name, KEY_BINARY, KEY_END };
	if (!node.IsNull ())
	{
		try
		{
			key.set<bool> (node.as<bool> ());
		}
		catch (YAML::BadConversion const &)
		{
			key.setString (node.as<string> ());
		}
	}
	if (node.Tag () == "tag:yaml.org,2002:binary")
	{
		ELEKTRA_LOG_DEBUG ("Set metadata type of key to binary");
		key.setMeta ("type", "binary");
	}
	ELEKTRA_LOG_DEBUG ("Add key “%s: %s”", key.getName ().c_str (),
			   key.getBinarySize () == 0 ? "NULL" : key.isBinary () ? "binary value!" : key.get<string> ().c_str ());
	return key;
}

/**
 * @brief Convert the key value of a YAML meta node to a key
 *
 * @param node This YAML meta node stores the data this function stores in the returned key
 * @param parent This key stores the prefix for the key name
 *
 * @return A key representing the key value stored in `node`
 */
Key convertMetaNodeToKey (YAML::Node const & node, Key & parent)
{
	auto key = node[0].IsNull () ? Key{ parent.getFullName (), KEY_BINARY, KEY_END } :
				       Key{ parent.getFullName (), KEY_VALUE, node[0].as<string> ().c_str (), KEY_END };
	ELEKTRA_LOG_DEBUG ("Add key “%s”: “%s”", key.getName ().c_str (),
			   key.getBinarySize () == 0 ? "NULL" : key.isString () ? key.getString ().c_str () : "binary value!");
	return key;
}

/**
 * @brief Convert a YAML node to a key set
 *
 * @param node This YAML node stores the data that should be added to the keyset `mappings`
 * @param mappings The key set where the YAML data will be stored
 * @param parent This key stores the prefix for the key name
 */
void convertNodeToKeySet (YAML::Node const & node, KeySet & mappings, Key & parent)
{
	if (node.Tag () == "!elektra/meta")
	{
		auto key = convertMetaNodeToKey (node, parent);
		mappings.append (key);
		addMetadata (key, node[1]);
	}
	else if (node.IsScalar () || node.IsNull ())
	{
		auto key = createLeafKey (node, parent.getFullName ());
		mappings.append (key);
	}
	else if (node.IsMap () || node.IsSequence ())
	{
		for (auto element : node)
		{
			Key key = node.IsMap () ? newKey (element.first.as<string> (), parent) : newArrayKey (mappings, parent);
			if (!node.IsMap ()) mappings.append (parent); // Update array metadata

			convertNodeToKeySet (node.IsMap () ? element.second : element, mappings, key);
		}
	}
}
} // end namespace

/**
 * @brief Read a YAML file and add the resulting data to a given key set
 *
 * @param mappings The key set where the YAML data will be stored
 * @param parent This key stores the path to the YAML data file that should be read
 */
void yamlcpp::yamlRead (KeySet & mappings, Key & parent)
{
	YAML::Node config = YAML::LoadFile (parent.getString ());

#ifdef HAVE_LOGGER
	ostringstream data;
	data << config;

	ELEKTRA_LOG_DEBUG ("Read Data:");
	ELEKTRA_LOG_DEBUG ("——————————");

	istringstream stream (data.str ());
	for (string line; std::getline (stream, line);)
	{
		ELEKTRA_LOG_DEBUG ("%s", line.c_str ());
	}

	ELEKTRA_LOG_DEBUG ("——————————");
#endif

	convertNodeToKeySet (config, mappings, parent);
	ELEKTRA_LOG_DEBUG ("Added %zd key%s", mappings.size (), mappings.size () == 1 ? "" : "s");
}
<commit_msg>YAML CPP: Improve read performance<commit_after>/**
 * @file
 *
 * @brief Read key sets using yaml-cpp
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include "read.hpp"
#include "yaml-cpp/yaml.h"

#include <kdb.hpp>
#include <kdbease.h>
#include <kdblogger.h>
#include <kdbplugin.h>

#include <sstream>

using namespace std;
using namespace kdb;

namespace
{
/**
 * @brief This function creates a new key from the given parameters.
 *
 * @param name This string specifies the postfix of the name of the key produced by this function.
 * @param parent This key specifies the prefix of the name of the key produced by this function.
 *
 * @returns The function returns a new key that combines the name of the parent key and `name`.
 */
Key newKey (string const & name, Key const & parent)
{
	ELEKTRA_LOG_DEBUG ("Add new key with base name “%s”", name.c_str ());

	Key key{ parent.getFullName (), KEY_BINARY, KEY_END };
	key.addBaseName (name);

	return key;
}

/**
 * @brief This function creates a new array key from the given parameters.
 *
 * @param mappings This argument specifies the key set of the new key this function creates.
 * @param arrayKey This argument specifies the key that represents the root of the array.
 *
 * @returns The function returns a new key that is part of the array represented by `arrayKey`.
 */
Key newArrayKey (KeySet const & mappings, Key & arrayKey)
{
	ELEKTRA_LOG_DEBUG ("Add new array element to array parent “%s”", arrayKey.getName ().c_str ());

	KeySet arrayEntries{ elektraArrayGet (*arrayKey, mappings.getKeySet ()) };

	if (arrayEntries.size () <= 0)
	{
		Key first = arrayKey.dup ();
		first.addBaseName ("#");
		arrayEntries.append (first);
	}

	Key newKey{ elektraArrayGetNextKey (arrayEntries.getKeySet ()) };
	arrayKey.setMeta ("array", newKey.getBaseName ());

	return newKey;
}

/**
 * @brief Add metadata saved in a YAML map to the specified key
 *
 * @param key This parameter saves the key to which this function should add the metadata stored in `node`.
 * @param node This YAML node stores a map containing metadata.
 */
void addMetadata (Key & key, YAML::Node const & node)
{
	for (auto & element : node)
	{
		auto metakey = element.first.as<string> ();
		auto metavalue = element.second.IsNull () ? "" : element.second.as<string> ();
		ELEKTRA_LOG_DEBUG ("Add metakey “%s: %s”", metakey.c_str (), metavalue.c_str ());
		key.setMeta (metakey, metavalue);
	}
}

/**
 * @brief Create a key containing a (possibly empty) value.
 *
 * @param node This YAML node stores the data that should be converted to a new `Key`.
 * @param name This text specifies the name of the key this function creates.
 *
 * @return A new key containing the data specified in `node`
 */
Key createLeafKey (YAML::Node const & node, string const & name)
{
	Key key{ name, KEY_BINARY, KEY_END };
	if (!node.IsNull ())
	{
		auto value = node.as<string> ();
		if (value == "true" || value == "false")
		{
			try
			{
				key.set<bool> (node.as<bool> ());
			}
			catch (YAML::BadConversion const &)
			{
				key.set<string> (value); // Save value as string, if `node` is a quoted scalar
			}
		}
		else
		{
			key.set<string> (value);
		}
	}
	if (node.Tag () == "tag:yaml.org,2002:binary")
	{
		ELEKTRA_LOG_DEBUG ("Set metadata type of key to binary");
		key.setMeta ("type", "binary");
	}
	ELEKTRA_LOG_DEBUG ("Add key “%s: %s”", key.getName ().c_str (),
			   key.getBinarySize () == 0 ? "NULL" : key.isBinary () ? "binary value!" : key.get<string> ().c_str ());
	return key;
}

/**
 * @brief Convert the key value of a YAML meta node to a key
 *
 * @param node This YAML meta node stores the data this function stores in the returned key
 * @param parent This key stores the prefix for the key name
 *
 * @return A key representing the key value stored in `node`
 */
Key convertMetaNodeToKey (YAML::Node const & node, Key & parent)
{
	auto key = node[0].IsNull () ? Key{ parent.getFullName (), KEY_BINARY, KEY_END } :
				       Key{ parent.getFullName (), KEY_VALUE, node[0].as<string> ().c_str (), KEY_END };
	ELEKTRA_LOG_DEBUG ("Add key “%s”: “%s”", key.getName ().c_str (),
			   key.getBinarySize () == 0 ? "NULL" : key.isString () ? key.getString ().c_str () : "binary value!");
	return key;
}

/**
 * @brief Convert a YAML node to a key set
 *
 * @param node This YAML node stores the data that should be added to the keyset `mappings`
 * @param mappings The key set where the YAML data will be stored
 * @param parent This key stores the prefix for the key name
 */
void convertNodeToKeySet (YAML::Node const & node, KeySet & mappings, Key & parent)
{
	if (node.Tag () == "!elektra/meta")
	{
		auto key = convertMetaNodeToKey (node, parent);
		mappings.append (key);
		addMetadata (key, node[1]);
	}
	else if (node.IsScalar () || node.IsNull ())
	{
		auto key = createLeafKey (node, parent.getFullName ());
		mappings.append (key);
	}
	else if (node.IsMap () || node.IsSequence ())
	{
		for (auto element : node)
		{
			Key key = node.IsMap () ? newKey (element.first.as<string> (), parent) : newArrayKey (mappings, parent);
			if (!node.IsMap ()) mappings.append (parent); // Update array metadata

			convertNodeToKeySet (node.IsMap () ? element.second : element, mappings, key);
		}
	}
}
} // end namespace

/**
 * @brief Read a YAML file and add the resulting data to a given key set
 *
 * @param mappings The key set where the YAML data will be stored
 * @param parent This key stores the path to the YAML data file that should be read
 */
void yamlcpp::yamlRead (KeySet & mappings, Key & parent)
{
	YAML::Node config = YAML::LoadFile (parent.getString ());

#ifdef HAVE_LOGGER
	ostringstream data;
	data << config;

	ELEKTRA_LOG_DEBUG ("Read Data:");
	ELEKTRA_LOG_DEBUG ("——————————");

	istringstream stream (data.str ());
	for (string line; std::getline (stream, line);)
	{
		ELEKTRA_LOG_DEBUG ("%s", line.c_str ());
	}

	ELEKTRA_LOG_DEBUG ("——————————");
#endif

	convertNodeToKeySet (config, mappings, parent);
	ELEKTRA_LOG_DEBUG ("Added %zd key%s", mappings.size (), mappings.size () == 1 ? "" : "s");
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include "consoleui.h"
#include "scientist.h"

using namespace std;

ConsoleUI::ConsoleUI()
{

}

// Should not contain logic for individual commands, that should be in separate functions!
void ConsoleUI::run()
{
    string command;
    do
    {
        cout << "Select one of the following options: " << endl;
        cout << "Add - add a programmer/computer scientist" << endl;
        cout << "List - add a programmer/computer scientist" << endl;
        cout << "Quit - end program" << endl;

        cin >> command;

        if(command == "add" || command == "Add" || command == "ADD") // Could possibly be improved upon
        {
           userMenuAdd();
        }
        if(command == "list" || command == "List" || command == "LIST") // Could possibly be improved upon
        {
           userMenuList();
        }
    }while(command != "quit");

}
void ConsoleUI::userMenuAdd()
{
    string name;
    char gender;
    int birthYear;
    int deathYear = 0;
    //int age = 22; // TEMP

    cout << "Enter the programmer's/computer scientist's name: ";
    cin >> name; // TODO - take in as ( GETLINE )

    cout << "Enter the programmer's/computer scientist's gender (m/f): ";
    cin >> gender;

    cout << "Enter the programmer's/computer scientist's year of birth: ";
    cin >> birthYear;

    cout << "Enter the programmer's/computer scientist's year of death (leave empty if not applicable): ";
    cin >> deathYear;

    Scientist newScientist(name, gender, birthYear, deathYear);
}
void ConsoleUI::userMenuList()
{
    vector<Scientist> scientist = _service.getScientist();

    cout << "Performer name:" << endl;
    cout << "===============" << endl;
    for (size_t i = 0; i< scientist.size(); ++i)
    {
        cout << scientist[i].getName() << endl;
    }
}

<commit_msg>Text fix<commit_after>#include <iostream>
#include <string>
#include "consoleui.h"
#include "scientist.h"

using namespace std;

ConsoleUI::ConsoleUI()
{

}

// Should not contain logic for individual commands, that should be in separate functions!
void ConsoleUI::run()
{
    string command;
    do
    {
        cout << "Select one of the following options: " << endl;
        cout << "Add - add a programmer/computer scientist" << endl;
        cout << "List - add a programmer/computer scientist" << endl;
        cout << "Quit - end program" << endl;

        cin >> command;

        if(command == "add" || command == "Add" || command == "ADD") // Could possibly be improved upon
        {
           userMenuAdd();
        }
        if(command == "list" || command == "List" || command == "LIST") // Could possibly be improved upon
        {
           userMenuList();
        }
    }while(command != "quit");

}
void ConsoleUI::userMenuAdd()
{
    string name;
    char gender;
    int birthYear;
    int deathYear = 0;
    //int age = 22; // TEMP

    cout << "Enter the programmer's/computer scientist's name: ";
    cin >> name; // TODO - take in as ( GETLINE )

    cout << "Enter the programmer's/computer scientist's gender (m/f): ";
    cin >> gender;

    cout << "Enter the programmer's/computer scientist's year of birth: ";
    cin >> birthYear;

    cout << "Enter the programmer's/computer scientist's year of death (leave empty if not applicable): ";
    cin >> deathYear;

    Scientist newScientist(name, gender, birthYear, deathYear);
}
void ConsoleUI::userMenuList()
{
    vector<Scientist> scientist = _service.getScientist();

    cout << "Scientist name:" << endl;
    cout << "===============" << endl;
    for (size_t i = 0; i< scientist.size(); ++i)
    {
        cout << scientist[i].getName() << endl;
    }
}

<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include "consoleui.h"
#include "scientist.h"

using namespace std;

ConsoleUI::ConsoleUI()
{
    _service.getScientists();  // gets information from file so it's used from the beginning.
}

// Should not contain logic for individual commands, that should be in separate functions!
void ConsoleUI::run()
{

    string command;
    while(true)
    {
        cout << "Select one of the following options: " << endl;
        cout << "=====================================" << endl;
        cout << "Add - add a programmer/computer scientist" << endl;
        cout << "Remove - remove a programmer/computer scientist" << endl;
        cout << "List - show a list of all programmer's/computer scientist's" << endl;
        cout << "Search - search the list of programmer's/computer scientist's" << endl;
        cout << "Sort - sort list by name, gender, age or year of death" << endl;
        cout << "Quit - end program" << endl;

        cin >> command;
        for(unsigned int i = 0; i < command.length(); i++) // to make all lowercase, taken from c++ site
        {
            command[i] = tolower(command[i]);
        }

        if(command == "add")
        {
           userMenuAdd();
        }
        else if(command == "remove")
        {
           userMenuRemove();
        }
        else if(command == "list")
        {
           userMenuList();
        }
        else if(command == "search")
        {
           userMenuSearch();
        }
        else if(command == "sort")
        {
            userMenuSort();
        }
        else if(command == "quit")
        {
            break;
        }
        else
        {
            cout << "Invalid input" << endl;
        }
    }

}
void ConsoleUI::userMenuAdd()
{
    string name;
    char gender;
    int birthYear;
    int deathYear = 0;
    int age = 0;
    int a;

    while(true)
    {
        cout << "Enter the programmer's/computer scientist's name: ";
        cin.ignore();
        getline(cin, name);

        // Check for gender
        while(true)
        {
            cout << "Enter the programmer's/computer scientist's gender (m/f): ";
            cin >> gender;

            if((gender != 'm') && (gender != 'f'))
            {
                cout << "Invalid input" << endl;
            }
            else
            {
                break;
            }

        }

        // Check year of birth
        while(true)
        {
            cout << "Enter the programmer's/computer scientist's year of birth: ";
            cin >> birthYear;
            if(birthYear < 2016) // Just in case we find a programmer of the univers
            {
                break;
            }
            else
            {
                cout << "Invalid input" << endl;
            }
        }

        // Check when year of death (if dead)
        while(true)
        {
            cout << "Enter the programmer's/computer scientist's year of death (type 0 if not applicable): ";
            cin >> deathYear;
            if (deathYear == 0)
            {
                break;
            }
            else if(deathYear >= birthYear)
            {
                break;
            }
            else
            {
                cout << "Invalid input" << endl;
            }
        }

        // Check if input is correct
        cout << "Name: " << name << endl << "Gender: " << gender << endl << "Born: " << birthYear << endl;

        if(deathYear != 0)
        {
            cout << "Died: " << deathYear << endl;
        }
        else
        {
            cout << endl;
        }

        a = userCheckInput();
        if (a == 0)
        {
            _service.addScientist(name, gender, birthYear, deathYear, age);
            break;
        }
        else if (a == 2)
        {
            break;
        }

    }
    cout << endl;

}
void ConsoleUI::userMenuList()
{
    vector<Scientist> scientist = _service.getScientists();
    userMenuPrint(scientist);
}
void ConsoleUI::userMenuSearch()
{
    string command;
    cout << "Select a search option: " << endl;
    cout << "Name - Search by name" << endl;
    cout << "Gender - Search by gender" << endl;
    cout << "Age - Search by age" << endl;
    cout << "Birth - search by year of birth" << endl;
    cout << "Death - search by year of death" << endl;
    cin >> command;
    cout << endl;

    for(unsigned int i = 0; i < command.length(); i++) // to make all lowercase, taken from c++ site
    {
        command[i] = tolower(command[i]);
    }

    if(command == "name")
    {
        string userInputName;
        cout << "Search by name: ";
        cin.ignore();
        getline(cin, userInputName);

        vector<Scientist> scientist = _service.findScientistByName(userInputName);
        userMenuPrint(scientist);

    }
    else if(command == "gender") // findScientistByGender
    {
        char userInputGender;
        cout << "Search by gender: ";
        cin >> userInputGender;

        vector<Scientist> scientist = _service.findScientistByGender(userInputGender);
        userMenuPrint(scientist);
    }
    else if(command == "age") // findScientistByGender
    {
        int userInputAge;
        cout << "Search by age: ";
        cin >> userInputAge;

        vector<Scientist> scientist = _service.findScientistByAge(userInputAge);
        userMenuPrint(scientist);
    }
    else if(command == "birth")
    {
        int userInputBirth;
        cout << "Search by year of birth: ";
        cin >> userInputBirth;

        vector<Scientist> scientist = _service.findScientistByBirth(userInputBirth);
        userMenuPrint(scientist);
    }
    else if(command == "death")
    {
        int userInputDeath;
        cout << "Search by year of death (0 for still alive): ";
        cin >> userInputDeath;

        vector<Scientist> scientist = _service.findScientistByDeath(userInputDeath);
        userMenuPrint(scientist);
    }
    cout << endl;

}
void ConsoleUI::userMenuSort()
{
    int userInput;
    cout << "Sort list by Name A-Z(1), Name Z-A(2), Gender(3), Year of Birth(4), Year of Death(5) or Age (6)" << endl;
    cin >> userInput;
     _service.scientistSort(userInput);
     userMenuList();
}
void ConsoleUI::userMenuPrint(vector<Scientist>scientist)
{
    cout << endl;
    cout << "Scientist name:    gender:     born:   died:   age: " << endl;
    cout << "====================================================" << endl;
    for (size_t i = 0; i< scientist.size(); ++i)
    {
        cout << scientist[i].getName() << "\t"
             << scientist[i].getGender() << "\t"
             << scientist[i].getBirth() << "\t";

             if(scientist[i].getDeath() == 0)
             {
                 cout << "-" << "\t";
             }
             else
             {
                 cout << scientist[i].getDeath() << "\t";
             }
             cout << scientist[i].getAge() << endl;

    }
    cout << endl;
}
int  ConsoleUI::userCheckInput()
{
    // Check if all data is correct
    while(true)
    {
        char answear;
        cout << "Is this data correct? (input y/n) or press q to quit" << endl;
        cin >> answear;

        if(answear == 'y')
        {
            return 0;
        }
        else if (answear == 'n')
        {
            return 1;
        }
        else if (answear == 'q')
        {
            return 2;
        }
        else
        {
            cout << "Invalid input!";
        }

    }
}
void ConsoleUI::userMenuRemove()
{
    string userInputName;
    cout << "Remove a programmer/computer scientist: ";
    cin.ignore();
    getline(cin, userInputName);

    _service.removeScientist(userInputName);
}
<commit_msg>ui update<commit_after>#include <iostream>
#include <string>
#include "consoleui.h"
#include "scientist.h"

using namespace std;

ConsoleUI::ConsoleUI()
{
    _service.getScientists();  // gets information from file so it's used from the beginning.
}

// Should not contain logic for individual commands, that should be in separate functions!
void ConsoleUI::run()
{

    string command;
    while(true)
    {
        cout << "Select one of the following options: " << endl;
        cout << "=====================================" << endl;
        cout << "Add - add a programmer/computer scientist" << endl;
        cout << "Remove - remove a programmer/computer scientist" << endl;
        cout << "List - show a list of all programmer's/computer scientist's" << endl;
        cout << "Search - search the list of programmer's/computer scientist's" << endl;
        cout << "Sort - sort list by name, gender, age or year of death" << endl;
        cout << "Quit - end program" << endl;

        cin >> command;
        for(unsigned int i = 0; i < command.length(); i++) // to make all lowercase, taken from c++ site
        {
            command[i] = tolower(command[i]);
        }

        if(command == "add")
        {
           userMenuAdd();
        }
        else if(command == "remove")
        {
           userMenuRemove();
        }
        else if(command == "list")
        {
           userMenuList();
        }
        else if(command == "search")
        {
           userMenuSearch();
        }
        else if(command == "sort")
        {
            userMenuSort();
        }
        else if(command == "quit")
        {
            break;
        }
        else
        {
            cout << "Invalid input" << endl;
        }
    }

}
void ConsoleUI::userMenuAdd()
{
    string name;
    char gender;
    int birthYear;
    int deathYear = 0;
    int age = 0;
    int a;

    while(true)
    {
        cout << "Enter the programmer's/computer scientist's name: ";
        cin.ignore();
        getline(cin, name);

        // Check for gender
        while(true)
        {
            cout << "Enter the programmer's/computer scientist's gender (m/f): ";
            cin >> gender;

            if((gender != 'm') && (gender != 'f'))
            {
                cout << "Invalid input" << endl;
            }
            else
            {
                break;
            }

        }

        // Check year of birth
        while(true)
        {
            cout << "Enter the programmer's/computer scientist's year of birth: ";
            cin >> birthYear;
            if(birthYear < 2016) // Just in case we find a programmer of the univers
            {
                break;
            }
            else
            {
                cout << "Invalid input" << endl;
            }
        }

        // Check when year of death (if dead)
        while(true)
        {
            cout << "Enter the programmer's/computer scientist's year of death (type 0 if not applicable): ";
            cin >> deathYear;
            if (deathYear == 0)
            {
                break;
            }
            else if(deathYear >= birthYear)
            {
                break;
            }
            else
            {
                cout << "Invalid input" << endl;
            }
        }

        // Check if input is correct
        cout << "Name: " << name << endl << "Gender: " << gender << endl << "Born: " << birthYear << endl;

        if(deathYear != 0)
        {
            cout << "Died: " << deathYear << endl;
        }
        else
        {
            cout << endl;
        }

        a = userCheckInput();
        if (a == 0)
        {
            _service.addScientist(name, gender, birthYear, deathYear, age);
            break;
        }
        else if (a == 2)
        {
            break;
        }

    }
    cout << endl;

}
void ConsoleUI::userMenuList()
{
    vector<Scientist> scientist = _service.getScientists();
    userMenuPrint(scientist);
}
void ConsoleUI::userMenuSearch()
{
    string command;
    cout << "Select a search option: " << endl;
    cout << "Name - Search by name" << endl;
    cout << "Gender - Search by gender" << endl;
    cout << "Age - Search by age" << endl;
    cout << "Birth - search by year of birth" << endl;
    cout << "Death - search by year of death" << endl;
    cin >> command;
    cout << endl;

    for(unsigned int i = 0; i < command.length(); i++) // to make all lowercase, taken from c++ site
    {
        command[i] = tolower(command[i]);
    }

    if(command == "name")
    {
        string userInputName;
        cout << "Search by name: ";
        cin.ignore();
        getline(cin, userInputName);

        vector<Scientist> scientist = _service.findScientistByName(userInputName);
        userMenuPrint(scientist);

    }
    else if(command == "gender") // findScientistByGender
    {
        char userInputGender;
        cout << "Search by gender: ";
        cin >> userInputGender;

        vector<Scientist> scientist = _service.findScientistByGender(userInputGender);
        userMenuPrint(scientist);
    }
    else if(command == "age") // findScientistByGender
    {
        int userInputAge;
        cout << "Search by age: ";
        cin >> userInputAge;

        vector<Scientist> scientist = _service.findScientistByAge(userInputAge);
        userMenuPrint(scientist);
    }
    else if(command == "birth")
    {
        int userInputBirth;
        cout << "Search by year of birth: ";
        cin >> userInputBirth;

        vector<Scientist> scientist = _service.findScientistByBirth(userInputBirth);
        userMenuPrint(scientist);
    }
    else if(command == "death")
    {
        int userInputDeath;
        cout << "Search by year of death (0 for still alive): ";
        cin >> userInputDeath;

        vector<Scientist> scientist = _service.findScientistByDeath(userInputDeath);
        userMenuPrint(scientist);
    }
    cout << endl;

}
void ConsoleUI::userMenuSort()
{
    int userInput;
    cout << "Sort list by Name A-Z(1), Name Z-A(2), Gender(3), Year of Birth(4), Year of Death(5) or Age (6)" << endl;
    cin >> userInput;
     _service.scientistSort(userInput);
     userMenuList();
}
void ConsoleUI::userMenuPrint(vector<Scientist>scientist)
{
    cout << string( 100, '\n' );
    cout << "Scientist name:    gender:     born:   died:   age: " << endl;
    cout << "====================================================" << endl;
    for (size_t i = 0; i< scientist.size(); ++i)
    {
        cout << scientist[i].getName()   << "\t"
             << scientist[i].getGender() << "\t"
             << scientist[i].getBirth()  << "\t";

             if(scientist[i].getDeath() == 0)
             {
                 cout << "-" << "\t";
             }
             else
             {
                 cout << scientist[i].getDeath() << "\t";
             }
             cout << scientist[i].getAge() << endl;

    }
    cout << endl;
}
int  ConsoleUI::userCheckInput()
{
    // Check if all data is correct
    while(true)
    {
        char answear;
        cout << "Is this data correct? (input y/n) or press q to quit" << endl;
        cin >> answear;

        if(answear == 'y')
        {
            return 0;
        }
        else if (answear == 'n')
        {
            return 1;
        }
        else if (answear == 'q')
        {
            return 2;
        }
        else
        {
            cout << "Invalid input!";
        }

    }
}
void ConsoleUI::userMenuRemove()
{
    string userInputName;
    cout << "Remove a programmer/computer scientist: ";
    cin.ignore();
    getline(cin, userInputName);

    _service.removeScientist(userInputName);
}
<|endoftext|>


<commit_before>// -----------------------------------------------------------------
// libpion: a C++ framework for building lightweight HTTP interfaces
// -----------------------------------------------------------------
// Copyright (C) 2007 Atomic Labs, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#include <libpion/HTTPServer.hpp>
#include <libpion/HTTPRequest.hpp>
#include <libpion/HTTPResponse.hpp>
#include <libpion/HTTPRequestParser.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>

namespace pion {	// begin namespace pion

// HTTPServer member functions

void HTTPServer::handleConnection(TCPConnectionPtr& tcp_conn)
{
	HTTPRequestParserPtr request_parser(HTTPRequestParser::create(boost::bind(&HTTPServer::handleRequest,
																			  this, _1, _2), tcp_conn));
	request_parser->readRequest();
}

void HTTPServer::handleRequest(HTTPRequestPtr& http_request,
							   TCPConnectionPtr& tcp_conn)
{
	if (! http_request->isValid()) {
		// the request is invalid or an error occured
		LOG4CXX_INFO(m_logger, "Received an invalid HTTP request");
		tcp_conn->setKeepAlive(false);
		if (! m_bad_request_module->handleRequest(http_request, tcp_conn)) {
			// this shouldn't ever happen, but just in case
			tcp_conn->finish();
		}
		return;
	}

	LOG4CXX_DEBUG(m_logger, "Received a valid HTTP request");

	// set the connection's keep_alive flag
	tcp_conn->setKeepAlive(http_request->checkKeepAlive());

	// strip off trailing slash if the request has one
	std::string resource(http_request->getResource());
	if (! resource.empty() && resource[resource.size() - 1] == '/')
		resource.resize( resource.size() - 1 );

	// true if a module successfully handled the request
	bool request_was_handled = false;

	if (m_modules.empty()) {

		// no modules configured
		LOG4CXX_WARN(m_logger, "No modules configured");

	} else {

		// lock mutex for thread safety (this should probably use ref counters)
		boost::mutex::scoped_lock modules_lock(m_mutex);

		// iterate through each module that may be able to handle the request
		ModuleMap::iterator i = m_modules.upper_bound(resource);
		while (i != m_modules.begin()) {
			--i;
			// keep checking while the first part of the strings match
			if (i->second->checkResource(resource)) {

				// try to handle the request with the module
				request_was_handled = i->second->handleRequest(http_request, tcp_conn);

				if (request_was_handled) {
					// the module successfully handled the request
					LOG4CXX_DEBUG(m_logger, "HTTP request handled by module: "
								  <second->getResource());
					break;
				}
			} else {
				// we've gone to far; the first part no longer matches
				break;
			}
		}
	}

	if (! request_was_handled) {
		// no modules found that could handle the request
		LOG4CXX_INFO(m_logger, "No modules found to handle HTTP request: " << resource);
		if (! m_not_found_module->handleRequest(http_request, tcp_conn)) {
			// this shouldn't ever happen, but just in case
			tcp_conn->finish();
		}
	}
}

void HTTPServer::addModule(HTTPModulePtr m)
{
	boost::mutex::scoped_lock modules_lock(m_mutex);
	m_modules.insert(std::make_pair(m->getResource(), m));
}

void HTTPServer::clearModules(void)
{
	boost::mutex::scoped_lock modules_lock(m_mutex);
	m_modules.clear();
}

// static members of HTTPServer::BadRequestModule

const std::string HTTPServer::BadRequestModule::BAD_REQUEST_HTML =
	"The request is invalid\r\n\r\n";

// HTTPServer::BadRequestModule member functions

bool HTTPServer::BadRequestModule::handleRequest(HTTPRequestPtr& request,
												 TCPConnectionPtr& tcp_conn)
{
	HTTPResponsePtr response(HTTPResponse::create());
	response->setResponseCode(HTTPTypes::RESPONSE_CODE_BAD_REQUEST);
	response->setResponseMessage(HTTPTypes::RESPONSE_MESSAGE_BAD_REQUEST);
	response->writeNoCopy(BAD_REQUEST_HTML);
	response->send(tcp_conn);
	return true;
}

// static members of HTTPServer::NotFoundModule

const std::string HTTPServer::NotFoundModule::NOT_FOUND_HTML =
	"Request Not Found\r\n\r\n";

// HTTPServer::BadRequestModule member functions

bool HTTPServer::NotFoundModule::handleRequest(HTTPRequestPtr& request,
											   TCPConnectionPtr& tcp_conn)
{
	HTTPResponsePtr response(HTTPResponse::create());
	response->setResponseCode(HTTPTypes::RESPONSE_CODE_NOT_FOUND);
	response->setResponseMessage(HTTPTypes::RESPONSE_MESSAGE_NOT_FOUND);
	response->writeNoCopy(NOT_FOUND_HTML);
	response->send(tcp_conn);
	return true;
}

}	// end namespace pion

<commit_msg>Patched an infinite loop that occurred when a connection was closed while parsing the request<commit_after>// -----------------------------------------------------------------
// libpion: a C++ framework for building lightweight HTTP interfaces
// -----------------------------------------------------------------
// Copyright (C) 2007 Atomic Labs, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#include <libpion/HTTPServer.hpp>
#include <libpion/HTTPRequest.hpp>
#include <libpion/HTTPResponse.hpp>
#include <libpion/HTTPRequestParser.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>

namespace pion {	// begin namespace pion

// HTTPServer member functions

void HTTPServer::handleConnection(TCPConnectionPtr& tcp_conn)
{
	tcp_conn->setKeepAlive(false);	// default to closing the connection
	HTTPRequestParserPtr request_parser(HTTPRequestParser::create(boost::bind(&HTTPServer::handleRequest,
																			  this, _1, _2), tcp_conn));
	request_parser->readRequest();
}

void HTTPServer::handleRequest(HTTPRequestPtr& http_request,
							   TCPConnectionPtr& tcp_conn)
{
	if (! http_request->isValid()) {
		// the request is invalid or an error occured
		LOG4CXX_INFO(m_logger, "Received an invalid HTTP request");
		if (! m_bad_request_module->handleRequest(http_request, tcp_conn)) {
			// this shouldn't ever happen, but just in case
			tcp_conn->finish();
		}
		return;
	}

	LOG4CXX_DEBUG(m_logger, "Received a valid HTTP request");

	// set the connection's keep_alive flag
	tcp_conn->setKeepAlive(http_request->checkKeepAlive());

	// strip off trailing slash if the request has one
	std::string resource(http_request->getResource());
	if (! resource.empty() && resource[resource.size() - 1] == '/')
		resource.resize( resource.size() - 1 );

	// true if a module successfully handled the request
	bool request_was_handled = false;

	if (m_modules.empty()) {

		// no modules configured
		LOG4CXX_WARN(m_logger, "No modules configured");

	} else {

		// lock mutex for thread safety (this should probably use ref counters)
		boost::mutex::scoped_lock modules_lock(m_mutex);

		// iterate through each module that may be able to handle the request
		ModuleMap::iterator i = m_modules.upper_bound(resource);
		while (i != m_modules.begin()) {
			--i;
			// keep checking while the first part of the strings match
			if (i->second->checkResource(resource)) {

				// try to handle the request with the module
				request_was_handled = i->second->handleRequest(http_request, tcp_conn);

				if (request_was_handled) {
					// the module successfully handled the request
					LOG4CXX_DEBUG(m_logger, "HTTP request handled by module: "
								  <second->getResource());
					break;
				}
			} else {
				// we've gone to far; the first part no longer matches
				break;
			}
		}
	}

	if (! request_was_handled) {
		// no modules found that could handle the request
		LOG4CXX_INFO(m_logger, "No modules found to handle HTTP request: " << resource);
		if (! m_not_found_module->handleRequest(http_request, tcp_conn)) {
			// this shouldn't ever happen, but just in case
			tcp_conn->finish();
		}
	}
}

void HTTPServer::addModule(HTTPModulePtr m)
{
	boost::mutex::scoped_lock modules_lock(m_mutex);
	m_modules.insert(std::make_pair(m->getResource(), m));
}

void HTTPServer::clearModules(void)
{
	boost::mutex::scoped_lock modules_lock(m_mutex);
	m_modules.clear();
}

// static members of HTTPServer::BadRequestModule

const std::string HTTPServer::BadRequestModule::BAD_REQUEST_HTML =
	"The request is invalid\r\n\r\n";

// HTTPServer::BadRequestModule member functions

bool HTTPServer::BadRequestModule::handleRequest(HTTPRequestPtr& request,
												 TCPConnectionPtr& tcp_conn)
{
	HTTPResponsePtr response(HTTPResponse::create());
	response->setResponseCode(HTTPTypes::RESPONSE_CODE_BAD_REQUEST);
	response->setResponseMessage(HTTPTypes::RESPONSE_MESSAGE_BAD_REQUEST);
	response->writeNoCopy(BAD_REQUEST_HTML);
	response->send(tcp_conn);
	return true;
}

// static members of HTTPServer::NotFoundModule

const std::string HTTPServer::NotFoundModule::NOT_FOUND_HTML =
	"Request Not Found\r\n\r\n";

// HTTPServer::BadRequestModule member functions

bool HTTPServer::NotFoundModule::handleRequest(HTTPRequestPtr& request,
											   TCPConnectionPtr& tcp_conn)
{
	HTTPResponsePtr response(HTTPResponse::create());
	response->setResponseCode(HTTPTypes::RESPONSE_CODE_NOT_FOUND);
	response->setResponseMessage(HTTPTypes::RESPONSE_MESSAGE_NOT_FOUND);
	response->writeNoCopy(NOT_FOUND_HTML);
	response->send(tcp_conn);
	return true;
}

}	// end namespace pion

<|endoftext|>


<commit_before>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2004-2007 Torsten Rahn <tackat@kde.org>"
// Copyright 2007      Inge Wallin  <ingwa@kde.org>"
//

#include "MarbleDirs.h"

#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtGui/QApplication>

#ifdef Q_OS_MACX
//for getting app bundle path
#include <ApplicationServices/ApplicationServices.h>
#endif

#ifdef Q_OS_WIN
//for getting appdata path
#define _WIN32_IE 0x0400
#include <shlobj.h>
#endif

#include <config-marble.h>

namespace
{
    QString runTimeMarbleDataPath = "";

    QString runTimeMarblePluginPath = "";
}

MarbleDirs::MarbleDirs()
    : d( 0 )
{
}

QString MarbleDirs::path( const QString& relativePath )
{
    QString  localpath = localPath() + '/' + relativePath;	// local path
    QString  systempath  = systemPath() + '/' + relativePath;	// system path

    QString fullpath = systempath;
    if ( QFile::exists( localpath ) ) {
        fullpath = localpath;
    }

    return QDir( fullpath ).canonicalPath();
}

QString MarbleDirs::pluginPath( const QString& relativePath )
{
    QString  localpath = pluginLocalPath() + QDir::separator() + relativePath;    // local path
    QString  systempath  = pluginSystemPath() + QDir::separator() + relativePath; // system path

    QString fullpath = systempath;
    if ( QFile::exists( localpath ) ) {
        fullpath = localpath;
    }

    return QDir( fullpath ).canonicalPath();
}

QStringList MarbleDirs::entryList( const QString& relativePath, QDir::Filters filters )
{
    QStringList filesLocal = QDir( MarbleDirs::localPath() + '/' + relativePath ).entryList(filters);
    QStringList filesSystem = QDir( MarbleDirs::systemPath() + '/' + relativePath ).entryList(filters);
    QStringList allFiles( filesLocal );
    allFiles << filesSystem;

    // remove duplicate entries
    allFiles.sort();
    for ( int i = 1; i < allFiles.size(); ++i ) {
        if ( allFiles.at(i) == allFiles.at( i - 1 ) ) {
            allFiles.removeAt(i);
            --i;
        }
    }

    for (int i = 0; i < allFiles.size(); ++i)
       qDebug() << "Files: " << allFiles.at(i);

    return allFiles;
}

QStringList MarbleDirs::pluginEntryList( const QString& relativePath, QDir::Filters filters )
{
    QStringList filesLocal = QDir( MarbleDirs::pluginLocalPath() + '/' + relativePath ).entryList(filters);
    QStringList filesSystem = QDir( MarbleDirs::pluginSystemPath() + '/' + relativePath ).entryList(filters);
    QStringList allFiles( filesLocal );
    allFiles << filesSystem;

    // remove duplicate entries
    allFiles.sort();
    for ( int i = 1; i < allFiles.size(); ++i ) {
        if ( allFiles.at(i) == allFiles.at( i - 1 ) ) {
            allFiles.removeAt(i);
            --i;
        }
    }

    for (int i = 0; i < allFiles.size(); ++i)
       qDebug() << "Files: " << allFiles.at(i);

    return allFiles;
}

QString MarbleDirs::systemPath()
{
    QString systempath;

#ifdef Q_OS_MACX
    //
    // On OSX lets try to find any file first in the bundle
    // before branching out to home and sys dirs
    //
    CFURLRef myBundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
    CFStringRef myMacPath = CFURLCopyFileSystemPath(myBundleRef, kCFURLPOSIXPathStyle);
    const char *mypPathPtr = CFStringGetCStringPtr(myMacPath,CFStringGetSystemEncoding());
    CFRelease(myBundleRef);
    CFRelease(myMacPath);
    QString myPath(mypPathPtr);
    //do some magick so that we can still find data dir if
    //marble was not built as a bundle
    if (myPath.contains(".app"))  //its a bundle!
    {
      systempath = myPath + "/Contents/Resources/data";
    }

    if ( QFile::exists( systempath ) ){
      return systempath;
    }
#endif   // mac bundle

// Should this happen before the Mac bundle already?
if ( !runTimeMarbleDataPath.isEmpty() )
    return runTimeMarbleDataPath;

#ifdef MARBLE_DATA_PATH
    //MARBLE_DATA_PATH is a compiler define set by cmake
    QString compileTimeMarbleDataPath(MARBLE_DATA_PATH);

    if(QDir(compileTimeMarbleDataPath).exists())
        return compileTimeMarbleDataPath;
#endif  // MARBLE_DATA_PATH

    return QDir( QCoreApplication::applicationDirPath()

#if defined(QTONLY)
                     + QLatin1String( "/data" )
#else
                     + QLatin1String( "/../share/apps/marble/data" )
#endif
                     ).canonicalPath();
}

QString MarbleDirs::pluginSystemPath()
{
    QString systempath;

#ifdef Q_OS_MACX
    //
    // On OSX lets try to find any file first in the bundle
    // before branching out to home and sys dirs
    //
    CFURLRef myBundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
    CFStringRef myMacPath = CFURLCopyFileSystemPath(myBundleRef, kCFURLPOSIXPathStyle);
    const char *mypPathPtr = CFStringGetCStringPtr(myMacPath,CFStringGetSystemEncoding());
    CFRelease(myBundleRef);
    CFRelease(myMacPath);
    QString myPath(mypPathPtr);
    //do some magick so that we can still find data dir if
    //marble was not built as a bundle
    if (myPath.contains(".app"))  //its a bundle!
    {
      systempath = myPath + "/Contents/Resources/plugins";
    }

    if ( QFile::exists( systempath ) ){
      return systempath;
    }
#endif   // mac bundle

// Should this happen before the Mac bundle already?
if ( !runTimeMarblePluginPath.isEmpty() )
    return runTimeMarblePluginPath;

#ifdef MARBLE_PLUGIN_PATH
    //MARBLE_PLUGIN_PATH is a compiler define set by cmake
    QString compileTimeMarblePluginPath(MARBLE_PLUGIN_PATH);

    if(QDir(compileTimeMarblePluginPath).exists())
        return compileTimeMarblePluginPath;
#endif  // MARBLE_PLUGIN_PATH

    return QDir( QCoreApplication::applicationDirPath()

#if defined(QTONLY)
                     + QLatin1String( "/plugins" )
#else
                     + QLatin1String( "/../lib/kde4/plugins/marble" )
#endif
                     ).canonicalPath();
}

QString MarbleDirs::localPath()
{
#ifndef Q_OS_WIN
    return QString( QDir::homePath() + "/.marble/data" ); // local path
#else
    HWND hwnd = 0;
    WCHAR *appdata_path = new WCHAR[MAX_PATH+1];

    SHGetSpecialFolderPathW( hwnd, appdata_path, CSIDL_APPDATA, 0 );
    QString appdata = QString::fromUtf16( reinterpret_cast<ushort*>( appdata_path ) );
    delete appdata_path;
    return QString( QDir::fromNativeSeparators( appdata ) + "/.marble/data" ); // local path
#endif
}

QString MarbleDirs::pluginLocalPath()
{
#ifndef Q_OS_WIN
    return QString( QDir::homePath() + "/.marble/plugins" ); // local path
#else
    HWND hwnd = 0;
    WCHAR *appdata_path = new WCHAR[MAX_PATH];

    SHGetSpecialFolderPathW( hwnd, appdata_path, CSIDL_APPDATA, 0 );
    QString appdata = QString::fromUtf16( reinterpret_cast<ushort*>( appdata_path ) );
    delete appdata_path;
    return QString( QDir::fromNativeSeparators( appdata ) + "/.marble/plugins" ); // local path
#endif
}

QString MarbleDirs::marbleDataPath()
{
    return runTimeMarbleDataPath;
}

QString MarbleDirs::marblePluginPath()
{
    return runTimeMarbleDataPath;
}

void MarbleDirs::setMarbleDataPath( const QString& adaptedPath )
{
    if ( !QDir::root().exists( adaptedPath ) )
    {
        qDebug( "WARNING: Invalid MarbleDataPath %s. Using builtin path instead.",
                qPrintable( adaptedPath ) );
        return;
    }

    runTimeMarbleDataPath = adaptedPath;
}

void MarbleDirs::setMarblePluginPath( const QString& adaptedPath )
{
    if ( !QDir::root().exists( adaptedPath ) )
    {
        qDebug( "WARNING: Invalid MarblePluginPath %s. Using builtin path instead.",
                qPrintable( adaptedPath ) );
        return;
    }

    runTimeMarblePluginPath = adaptedPath;
}

void MarbleDirs::debug()
{
    qDebug() << "=== MarbleDirs: ===";
    qDebug() << "Local Path:" << localPath();
    qDebug() << "Plugin Local Path:" << pluginLocalPath();
    qDebug() << "";
    qDebug() << "Marble Data Path (Run Time) :" << runTimeMarbleDataPath;
    qDebug() << "Marble Data Path (Compile Time):" << QString(MARBLE_DATA_PATH);
    qDebug() << "";
    qDebug() << "Marble Plugin Path (Run Time) :" << runTimeMarblePluginPath;
    qDebug() << "Marble Plugin Path (Compile Time):" << QString(MARBLE_PLUGIN_PATH);
    qDebug() << "";
    qDebug() << "System Path:" << systemPath();
    qDebug() << "Plugin System Path:" << pluginSystemPath();
    qDebug() << "===================";
}
<commit_msg>occurs twice<commit_after>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2004-2007 Torsten Rahn <tackat@kde.org>"
// Copyright 2007      Inge Wallin  <ingwa@kde.org>"
//

#include "MarbleDirs.h"

#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtGui/QApplication>

#ifdef Q_OS_MACX
//for getting app bundle path
#include <ApplicationServices/ApplicationServices.h>
#endif

#ifdef Q_OS_WIN
//for getting appdata path
#define _WIN32_IE 0x0400
#include <shlobj.h>
#endif

#include <config-marble.h>

namespace
{
    QString runTimeMarbleDataPath = "";

    QString runTimeMarblePluginPath = "";
}

MarbleDirs::MarbleDirs()
    : d( 0 )
{
}

QString MarbleDirs::path( const QString& relativePath )
{
    QString  localpath = localPath() + '/' + relativePath;	// local path
    QString  systempath  = systemPath() + '/' + relativePath;	// system path

    QString fullpath = systempath;
    if ( QFile::exists( localpath ) ) {
        fullpath = localpath;
    }

    return QDir( fullpath ).canonicalPath();
}

QString MarbleDirs::pluginPath( const QString& relativePath )
{
    QString  localpath = pluginLocalPath() + QDir::separator() + relativePath;    // local path
    QString  systempath  = pluginSystemPath() + QDir::separator() + relativePath; // system path

    QString fullpath = systempath;
    if ( QFile::exists( localpath ) ) {
        fullpath = localpath;
    }

    return QDir( fullpath ).canonicalPath();
}

QStringList MarbleDirs::entryList( const QString& relativePath, QDir::Filters filters )
{
    QStringList filesLocal = QDir( MarbleDirs::localPath() + '/' + relativePath ).entryList(filters);
    QStringList filesSystem = QDir( MarbleDirs::systemPath() + '/' + relativePath ).entryList(filters);
    QStringList allFiles( filesLocal );
    allFiles << filesSystem;

    // remove duplicate entries
    allFiles.sort();
    for ( int i = 1; i < allFiles.size(); ++i ) {
        if ( allFiles.at(i) == allFiles.at( i - 1 ) ) {
            allFiles.removeAt(i);
            --i;
        }
    }

    for (int i = 0; i < allFiles.size(); ++i)
       qDebug() << "Files: " << allFiles.at(i);

    return allFiles;
}

QStringList MarbleDirs::pluginEntryList( const QString& relativePath, QDir::Filters filters )
{
    QStringList filesLocal = QDir( MarbleDirs::pluginLocalPath() + '/' + relativePath ).entryList(filters);
    QStringList filesSystem = QDir( MarbleDirs::pluginSystemPath() + '/' + relativePath ).entryList(filters);
    QStringList allFiles( filesLocal );
    allFiles << filesSystem;

    // remove duplicate entries
    allFiles.sort();
    for ( int i = 1; i < allFiles.size(); ++i ) {
        if ( allFiles.at(i) == allFiles.at( i - 1 ) ) {
            allFiles.removeAt(i);
            --i;
        }
    }

    for (int i = 0; i < allFiles.size(); ++i)
       qDebug() << "Files: " << allFiles.at(i);

    return allFiles;
}

QString MarbleDirs::systemPath()
{
    QString systempath;

#ifdef Q_OS_MACX
    //
    // On OSX lets try to find any file first in the bundle
    // before branching out to home and sys dirs
    //
    CFURLRef myBundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
    CFStringRef myMacPath = CFURLCopyFileSystemPath(myBundleRef, kCFURLPOSIXPathStyle);
    const char *mypPathPtr = CFStringGetCStringPtr(myMacPath,CFStringGetSystemEncoding());
    CFRelease(myBundleRef);
    CFRelease(myMacPath);
    QString myPath(mypPathPtr);
    //do some magick so that we can still find data dir if
    //marble was not built as a bundle
    if (myPath.contains(".app"))  //its a bundle!
    {
      systempath = myPath + "/Contents/Resources/data";
    }

    if ( QFile::exists( systempath ) ){
      return systempath;
    }
#endif   // mac bundle

// Should this happen before the Mac bundle already?
if ( !runTimeMarbleDataPath.isEmpty() )
    return runTimeMarbleDataPath;

#ifdef MARBLE_DATA_PATH
    //MARBLE_DATA_PATH is a compiler define set by cmake
    QString compileTimeMarbleDataPath(MARBLE_DATA_PATH);

    if(QDir(compileTimeMarbleDataPath).exists())
        return compileTimeMarbleDataPath;
#endif  // MARBLE_DATA_PATH

    return QDir( QCoreApplication::applicationDirPath()

#if defined(QTONLY)
                     + QLatin1String( "/data" )
#else
                     + QLatin1String( "/../share/apps/marble/data" )
#endif
                     ).canonicalPath();
}

QString MarbleDirs::pluginSystemPath()
{
    QString systempath;

#ifdef Q_OS_MACX
    //
    // On OSX lets try to find any file first in the bundle
    // before branching out to home and sys dirs
    //
    CFURLRef myBundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
    CFStringRef myMacPath = CFURLCopyFileSystemPath(myBundleRef, kCFURLPOSIXPathStyle);
    const char *mypPathPtr = CFStringGetCStringPtr(myMacPath,CFStringGetSystemEncoding());
    CFRelease(myBundleRef);
    CFRelease(myMacPath);
    QString myPath(mypPathPtr);
    //do some magick so that we can still find data dir if
    //marble was not built as a bundle
    if (myPath.contains(".app"))  //its a bundle!
    {
      systempath = myPath + "/Contents/Resources/plugins";
    }

    if ( QFile::exists( systempath ) ){
      return systempath;
    }
#endif   // mac bundle

// Should this happen before the Mac bundle already?
if ( !runTimeMarblePluginPath.isEmpty() )
    return runTimeMarblePluginPath;

#ifdef MARBLE_PLUGIN_PATH
    //MARBLE_PLUGIN_PATH is a compiler define set by cmake
    QString compileTimeMarblePluginPath(MARBLE_PLUGIN_PATH);

    if(QDir(compileTimeMarblePluginPath).exists())
        return compileTimeMarblePluginPath;
#endif  // MARBLE_PLUGIN_PATH

    return QDir( QCoreApplication::applicationDirPath()

#if defined(QTONLY)
                     + QLatin1String( "/plugins" )
#else
                     + QLatin1String( "/../lib/kde4/plugins/marble" )
#endif
                     ).canonicalPath();
}

QString MarbleDirs::localPath()
{
#ifndef Q_OS_WIN
    return QString( QDir::homePath() + "/.marble/data" ); // local path
#else
    HWND hwnd = 0;
    WCHAR *appdata_path = new WCHAR[MAX_PATH+1];

    SHGetSpecialFolderPathW( hwnd, appdata_path, CSIDL_APPDATA, 0 );
    QString appdata = QString::fromUtf16( reinterpret_cast<ushort*>( appdata_path ) );
    delete appdata_path;
    return QString( QDir::fromNativeSeparators( appdata ) + "/.marble/data" ); // local path
#endif
}

QString MarbleDirs::pluginLocalPath()
{
#ifndef Q_OS_WIN
    return QString( QDir::homePath() + "/.marble/plugins" ); // local path
#else
    HWND hwnd = 0;
    WCHAR *appdata_path = new WCHAR[MAX_PATH+1];

    SHGetSpecialFolderPathW( hwnd, appdata_path, CSIDL_APPDATA, 0 );
    QString appdata = QString::fromUtf16( reinterpret_cast<ushort*>( appdata_path ) );
    delete appdata_path;
    return QString( QDir::fromNativeSeparators( appdata ) + "/.marble/plugins" ); // local path
#endif
}

QString MarbleDirs::marbleDataPath()
{
    return runTimeMarbleDataPath;
}

QString MarbleDirs::marblePluginPath()
{
    return runTimeMarbleDataPath;
}

void MarbleDirs::setMarbleDataPath( const QString& adaptedPath )
{
    if ( !QDir::root().exists( adaptedPath ) )
    {
        qDebug( "WARNING: Invalid MarbleDataPath %s. Using builtin path instead.",
                qPrintable( adaptedPath ) );
        return;
    }

    runTimeMarbleDataPath = adaptedPath;
}

void MarbleDirs::setMarblePluginPath( const QString& adaptedPath )
{
    if ( !QDir::root().exists( adaptedPath ) )
    {
        qDebug( "WARNING: Invalid MarblePluginPath %s. Using builtin path instead.",
                qPrintable( adaptedPath ) );
        return;
    }

    runTimeMarblePluginPath = adaptedPath;
}

void MarbleDirs::debug()
{
    qDebug() << "=== MarbleDirs: ===";
    qDebug() << "Local Path:" << localPath();
    qDebug() << "Plugin Local Path:" << pluginLocalPath();
    qDebug() << "";
    qDebug() << "Marble Data Path (Run Time) :" << runTimeMarbleDataPath;
    qDebug() << "Marble Data Path (Compile Time):" << QString(MARBLE_DATA_PATH);
    qDebug() << "";
    qDebug() << "Marble Plugin Path (Run Time) :" << runTimeMarblePluginPath;
    qDebug() << "Marble Plugin Path (Compile Time):" << QString(MARBLE_PLUGIN_PATH);
    qDebug() << "";
    qDebug() << "System Path:" << systemPath();
    qDebug() << "Plugin System Path:" << pluginSystemPath();
    qDebug() << "===================";
}
<|endoftext|>