<commit_before>/*
 * copyright (c) 2017 Matthew Oliver
 *
 * This file is part of ShiftMediaProject.
 *
 * ShiftMediaProject 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.
 *
 * ShiftMediaProject 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 ShiftMediaProject; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "projectGenerator.h"

#include <algorithm>
#include <utility>

bool ProjectGenerator::findSourceFile(const string & sFile, const string & sExtension, string & sRetFileName)
{
    string sFileName;
    sRetFileName = m_sProjectDir + sFile + sExtension;
    if (!findFile(sRetFileName, sFileName)) {
        // Check if this is a built file
        uint uiSPos = m_sProjectDir.rfind('/', m_sProjectDir.length() - 2);
        uiSPos = (uiSPos == string::npos) ? 0 : uiSPos + 1;
        string sProjectName = m_sProjectDir.substr(uiSPos);
        sProjectName = (m_sProjectDir.compare("./") != 0) ? sProjectName : "";
        sRetFileName = m_ConfigHelper.m_sSolutionDirectory + sProjectName + sFile + sExtension;
        if (!findFile(sRetFileName, sFileName)) {
            // Check if this file already includes the project folder in its name
            if(sFile.find(sProjectName) != string::npos) {
                sRetFileName = m_sProjectDir + sFile.substr(sFile.find(sProjectName) + sProjectName.length()) + sExtension;
                return findFile(sRetFileName, sFileName);
            }
            return false;
        }
    }
    return true;
}

bool ProjectGenerator::findSourceFiles(const string & sFile, const string & sExtension, vector<string> & vRetFiles)
{
    string sFileName = m_sProjectDir + sFile + sExtension;
    return findFiles(sFileName, vRetFiles);
}

bool ProjectGenerator::checkProjectFiles()
{
    //Check that all headers are correct
    for (StaticList::iterator itIt = m_vHIncludes.begin(); itIt != m_vHIncludes.end(); itIt++) {
        string sRetFileName;
        if (!findSourceFile(*itIt, ".h", sRetFileName)) {
            outputError("Could not find input header file for object (" + *itIt + ")");
            return false;
        }
        //Update the entry with the found file with complete path
        m_ConfigHelper.makeFileProjectRelative(sRetFileName, *itIt);
    }

    //Check that all C Source are correct
    for (StaticList::iterator itIt = m_vCIncludes.begin(); itIt != m_vCIncludes.end(); itIt++) {
        string sRetFileName;
        if (!findSourceFile(*itIt, ".c", sRetFileName)) {
            outputError("Could not find input C source file for object (" + *itIt + ")");
            return false;
        }
        //Update the entry with the found file with complete path
        m_ConfigHelper.makeFileProjectRelative(sRetFileName, *itIt);
    }

    //Check that all CPP Source are correct
    for (StaticList::iterator itIt = m_vCPPIncludes.begin(); itIt != m_vCPPIncludes.end(); itIt++) {
        string sRetFileName;
        if (!findSourceFile(*itIt, ".cpp", sRetFileName)) {
            outputError("Could not find input C++ source file for object (" + *itIt + ")");
            return false;
        }
        //Update the entry with the found file with complete path
        m_ConfigHelper.makeFileProjectRelative(sRetFileName, *itIt);
    }

    //Check that all ASM Source are correct
    for (StaticList::iterator itIt = m_vASMIncludes.begin(); itIt != m_vASMIncludes.end(); itIt++) {
        string sRetFileName;
        if (!findSourceFile(*itIt, ".asm", sRetFileName)) {
            outputError("Could not find input ASM source file for object (" + *itIt + ")");
            return false;
        }
        //Update the entry with the found file with complete path
        m_ConfigHelper.makeFileProjectRelative(sRetFileName, *itIt);
    }

    //Check the output Unknown Includes and find there corresponding file
    if (!findProjectFiles(m_vIncludes, m_vCIncludes, m_vCPPIncludes, m_vASMIncludes, m_vHIncludes)) {
        return false;
    }

    if (m_ConfigHelper.m_bDCEOnly) {
        //Don't need to check for replace files
        return true;
    }

    //Check all source files associated with replaced config values
    StaticList vReplaceIncludes, vReplaceCPPIncludes, vReplaceCIncludes, vReplaceASMIncludes;
    for (UnknownList::iterator itIt = m_mReplaceIncludes.begin(); itIt != m_mReplaceIncludes.end(); itIt++) {
        vReplaceIncludes.push_back(itIt->first);
    }
    if (!findProjectFiles(vReplaceIncludes, vReplaceCIncludes, vReplaceCPPIncludes, vReplaceASMIncludes, m_vHIncludes)) {
        return false;
    } else {
        //Need to create local files for any replace objects
        if (!createReplaceFiles(vReplaceCIncludes, m_vCIncludes)) {
            return false;
        }
        if (!createReplaceFiles(vReplaceCPPIncludes, m_vCPPIncludes)) {
            return false;
        }
        if (!createReplaceFiles(vReplaceASMIncludes, m_vASMIncludes)) {
            return false;
        }
    }

    return true;
}

bool ProjectGenerator::createReplaceFiles(const StaticList& vReplaceIncludes, StaticList& vExistingIncludes)
{
    for (StaticList::const_iterator itIt = vReplaceIncludes.cbegin(); itIt != vReplaceIncludes.cend(); itIt++) {
        //Check hasnt already been included as a fixed object
        if (find(vExistingIncludes.begin(), vExistingIncludes.end(), *itIt) != vExistingIncludes.end()) {
            //skip this item
            continue;
        }
        //Convert file to format required to search ReplaceIncludes
        uint uiExtPos = itIt->rfind('.');
        uint uiCutPos = itIt->rfind('/') + 1;
        string sFilename = itIt->substr(uiCutPos, uiExtPos - uiCutPos);
        string sExtension = itIt->substr(uiExtPos);
        //Get the files dynamic config requirement
        string sIdents;
        for (StaticList::iterator itIdents = m_mReplaceIncludes[sFilename].begin(); itIdents < m_mReplaceIncludes[sFilename].end(); itIdents++) {
            sIdents += *itIdents;
            if ((itIdents + 1) < m_mReplaceIncludes[sFilename].end()) {
                sIdents += " || ";
            }
        }
        //Create new file to wrap input object
        string sPrettyFile = "../" + *itIt;
        string sNewFile = getCopywriteHeader(sFilename + sExtension + " file wrapper for " + m_sProjectName);
        sNewFile += "\n\
\n\
#include \"config.h\"\n\
#if " + sIdents + "\n\
#   include \"" + sPrettyFile + "\"\n\
#endif";
        //Write output project
        if (!makeDirectory(m_ConfigHelper.m_sSolutionDirectory + m_sProjectName)) {
            outputError("Failed creating local " + m_sProjectName + " directory");
            return false;
        }
        string sOutFile = m_ConfigHelper.m_sSolutionDirectory + m_sProjectName + "/" + sFilename + "_wrap" + sExtension;
        if (!writeToFile(sOutFile, sNewFile)) {
            return false;
        }
        //Add the new file to list of objects
        m_ConfigHelper.makeFileProjectRelative(sOutFile, sOutFile);
        vExistingIncludes.push_back(sOutFile);
    }
    return true;
}

bool ProjectGenerator::findProjectFiles(const StaticList& vIncludes, StaticList& vCIncludes, StaticList& vCPPIncludes, StaticList& vASMIncludes, StaticList& vHIncludes)
{
    for (StaticList::const_iterator itIt = vIncludes.cbegin(); itIt != vIncludes.cend(); itIt++) {
        string sRetFileName;
        if (findSourceFile(*itIt, ".c", sRetFileName)) {
            //Found a C File to include
            if (find(vCIncludes.begin(), vCIncludes.end(), sRetFileName) != vCIncludes.end()) {
                //skip this item
                continue;
            }
            m_ConfigHelper.makeFileProjectRelative(sRetFileName, sRetFileName);
            vCIncludes.push_back(sRetFileName);
        } else if (findSourceFile(*itIt, ".cpp", sRetFileName)) {
            //Found a C++ File to include
            if (find(vCPPIncludes.begin(), vCPPIncludes.end(), sRetFileName) != vCPPIncludes.end()) {
                //skip this item
                continue;
            }
            m_ConfigHelper.makeFileProjectRelative(sRetFileName, sRetFileName);
            vCPPIncludes.push_back(sRetFileName);
        } else if (findSourceFile(*itIt, ".asm", sRetFileName)) {
            //Found a ASM File to include
            if (find(vASMIncludes.begin(), vASMIncludes.end(), sRetFileName) != vASMIncludes.end()) {
                //skip this item
                continue;
            }
            m_ConfigHelper.makeFileProjectRelative(sRetFileName, sRetFileName);
            vASMIncludes.push_back(sRetFileName);
        } else if (findSourceFile(*itIt, ".h", sRetFileName)) {
            //Found a H File to include
            if (find(vHIncludes.begin(), vHIncludes.end(), sRetFileName) != vHIncludes.end()) {
                //skip this item
                continue;
            }
            m_ConfigHelper.makeFileProjectRelative(sRetFileName, sRetFileName);
            vHIncludes.push_back(sRetFileName);
        } else {
            outputError("Could not find valid source file for object (" + *itIt + ")");
            return false;
        }
    }
    return true;
}<commit_msg>Check that replace "wrap" file hasnt been added multiple times to project.<commit_after>/*
 * copyright (c) 2017 Matthew Oliver
 *
 * This file is part of ShiftMediaProject.
 *
 * ShiftMediaProject 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.
 *
 * ShiftMediaProject 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 ShiftMediaProject; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "projectGenerator.h"

#include <algorithm>
#include <utility>

bool ProjectGenerator::findSourceFile(const string & sFile, const string & sExtension, string & sRetFileName)
{
    string sFileName;
    sRetFileName = m_sProjectDir + sFile + sExtension;
    if (!findFile(sRetFileName, sFileName)) {
        // Check if this is a built file
        uint uiSPos = m_sProjectDir.rfind('/', m_sProjectDir.length() - 2);
        uiSPos = (uiSPos == string::npos) ? 0 : uiSPos + 1;
        string sProjectName = m_sProjectDir.substr(uiSPos);
        sProjectName = (m_sProjectDir.compare("./") != 0) ? sProjectName : "";
        sRetFileName = m_ConfigHelper.m_sSolutionDirectory + sProjectName + sFile + sExtension;
        if (!findFile(sRetFileName, sFileName)) {
            // Check if this file already includes the project folder in its name
            if(sFile.find(sProjectName) != string::npos) {
                sRetFileName = m_sProjectDir + sFile.substr(sFile.find(sProjectName) + sProjectName.length()) + sExtension;
                return findFile(sRetFileName, sFileName);
            }
            return false;
        }
    }
    return true;
}

bool ProjectGenerator::findSourceFiles(const string & sFile, const string & sExtension, vector<string> & vRetFiles)
{
    string sFileName = m_sProjectDir + sFile + sExtension;
    return findFiles(sFileName, vRetFiles);
}

bool ProjectGenerator::checkProjectFiles()
{
    //Check that all headers are correct
    for (StaticList::iterator itIt = m_vHIncludes.begin(); itIt != m_vHIncludes.end(); itIt++) {
        string sRetFileName;
        if (!findSourceFile(*itIt, ".h", sRetFileName)) {
            outputError("Could not find input header file for object (" + *itIt + ")");
            return false;
        }
        //Update the entry with the found file with complete path
        m_ConfigHelper.makeFileProjectRelative(sRetFileName, *itIt);
    }

    //Check that all C Source are correct
    for (StaticList::iterator itIt = m_vCIncludes.begin(); itIt != m_vCIncludes.end(); itIt++) {
        string sRetFileName;
        if (!findSourceFile(*itIt, ".c", sRetFileName)) {
            outputError("Could not find input C source file for object (" + *itIt + ")");
            return false;
        }
        //Update the entry with the found file with complete path
        m_ConfigHelper.makeFileProjectRelative(sRetFileName, *itIt);
    }

    //Check that all CPP Source are correct
    for (StaticList::iterator itIt = m_vCPPIncludes.begin(); itIt != m_vCPPIncludes.end(); itIt++) {
        string sRetFileName;
        if (!findSourceFile(*itIt, ".cpp", sRetFileName)) {
            outputError("Could not find input C++ source file for object (" + *itIt + ")");
            return false;
        }
        //Update the entry with the found file with complete path
        m_ConfigHelper.makeFileProjectRelative(sRetFileName, *itIt);
    }

    //Check that all ASM Source are correct
    for (StaticList::iterator itIt = m_vASMIncludes.begin(); itIt != m_vASMIncludes.end(); itIt++) {
        string sRetFileName;
        if (!findSourceFile(*itIt, ".asm", sRetFileName)) {
            outputError("Could not find input ASM source file for object (" + *itIt + ")");
            return false;
        }
        //Update the entry with the found file with complete path
        m_ConfigHelper.makeFileProjectRelative(sRetFileName, *itIt);
    }

    //Check the output Unknown Includes and find there corresponding file
    if (!findProjectFiles(m_vIncludes, m_vCIncludes, m_vCPPIncludes, m_vASMIncludes, m_vHIncludes)) {
        return false;
    }

    if (m_ConfigHelper.m_bDCEOnly) {
        //Don't need to check for replace files
        return true;
    }

    //Check all source files associated with replaced config values
    StaticList vReplaceIncludes, vReplaceCPPIncludes, vReplaceCIncludes, vReplaceASMIncludes;
    for (UnknownList::iterator itIt = m_mReplaceIncludes.begin(); itIt != m_mReplaceIncludes.end(); itIt++) {
        vReplaceIncludes.push_back(itIt->first);
    }
    if (!findProjectFiles(vReplaceIncludes, vReplaceCIncludes, vReplaceCPPIncludes, vReplaceASMIncludes, m_vHIncludes)) {
        return false;
    } else {
        //Need to create local files for any replace objects
        if (!createReplaceFiles(vReplaceCIncludes, m_vCIncludes)) {
            return false;
        }
        if (!createReplaceFiles(vReplaceCPPIncludes, m_vCPPIncludes)) {
            return false;
        }
        if (!createReplaceFiles(vReplaceASMIncludes, m_vASMIncludes)) {
            return false;
        }
    }

    return true;
}

bool ProjectGenerator::createReplaceFiles(const StaticList& vReplaceIncludes, StaticList& vExistingIncludes)
{
    for (StaticList::const_iterator itIt = vReplaceIncludes.cbegin(); itIt != vReplaceIncludes.cend(); itIt++) {
        //Check hasnt already been included as a fixed object
        if (find(vExistingIncludes.begin(), vExistingIncludes.end(), *itIt) != vExistingIncludes.end()) {
            //skip this item
            continue;
        }
        //Convert file to format required to search ReplaceIncludes
        uint uiExtPos = itIt->rfind('.');
        uint uiCutPos = itIt->rfind('/') + 1;
        string sFilename = itIt->substr(uiCutPos, uiExtPos - uiCutPos);
        string sExtension = itIt->substr(uiExtPos);
        string sOutFile = m_ConfigHelper.m_sSolutionDirectory + m_sProjectName + "/" + sFilename + "_wrap" + sExtension;
        string sNewOutFile;
        m_ConfigHelper.makeFileProjectRelative(sOutFile, sNewOutFile);
        // Check hasnt already been included as a wrapped object
        if (find(vExistingIncludes.begin(), vExistingIncludes.end(), sNewOutFile) != vExistingIncludes.end()) {
            // skip this item
            outputInfo(sNewOutFile);
            continue;
        }
        //Get the files dynamic config requirement
        string sIdents;
        for (StaticList::iterator itIdents = m_mReplaceIncludes[sFilename].begin(); itIdents < m_mReplaceIncludes[sFilename].end(); itIdents++) {
            sIdents += *itIdents;
            if ((itIdents + 1) < m_mReplaceIncludes[sFilename].end()) {
                sIdents += " || ";
            }
        }
        //Create new file to wrap input object
        string sPrettyFile = "../" + *itIt;
        string sNewFile = getCopywriteHeader(sFilename + sExtension + " file wrapper for " + m_sProjectName);
        sNewFile += "\n\
\n\
#include \"config.h\"\n\
#if " + sIdents + "\n\
#   include \"" + sPrettyFile + "\"\n\
#endif";
        //Write output project
        if (!makeDirectory(m_ConfigHelper.m_sSolutionDirectory + m_sProjectName)) {
            outputError("Failed creating local " + m_sProjectName + " directory");
            return false;
        }
        if (!writeToFile(sOutFile, sNewFile)) {
            return false;
        }
        //Add the new file to list of objects
        vExistingIncludes.push_back(sNewOutFile);
    }
    return true;
}

bool ProjectGenerator::findProjectFiles(const StaticList& vIncludes, StaticList& vCIncludes, StaticList& vCPPIncludes, StaticList& vASMIncludes, StaticList& vHIncludes)
{
    for (StaticList::const_iterator itIt = vIncludes.cbegin(); itIt != vIncludes.cend(); itIt++) {
        string sRetFileName;
        if (findSourceFile(*itIt, ".c", sRetFileName)) {
            //Found a C File to include
            if (find(vCIncludes.begin(), vCIncludes.end(), sRetFileName) != vCIncludes.end()) {
                //skip this item
                continue;
            }
            m_ConfigHelper.makeFileProjectRelative(sRetFileName, sRetFileName);
            vCIncludes.push_back(sRetFileName);
        } else if (findSourceFile(*itIt, ".cpp", sRetFileName)) {
            //Found a C++ File to include
            if (find(vCPPIncludes.begin(), vCPPIncludes.end(), sRetFileName) != vCPPIncludes.end()) {
                //skip this item
                continue;
            }
            m_ConfigHelper.makeFileProjectRelative(sRetFileName, sRetFileName);
            vCPPIncludes.push_back(sRetFileName);
        } else if (findSourceFile(*itIt, ".asm", sRetFileName)) {
            //Found a ASM File to include
            if (find(vASMIncludes.begin(), vASMIncludes.end(), sRetFileName) != vASMIncludes.end()) {
                //skip this item
                continue;
            }
            m_ConfigHelper.makeFileProjectRelative(sRetFileName, sRetFileName);
            vASMIncludes.push_back(sRetFileName);
        } else if (findSourceFile(*itIt, ".h", sRetFileName)) {
            //Found a H File to include
            if (find(vHIncludes.begin(), vHIncludes.end(), sRetFileName) != vHIncludes.end()) {
                //skip this item
                continue;
            }
            m_ConfigHelper.makeFileProjectRelative(sRetFileName, sRetFileName);
            vHIncludes.push_back(sRetFileName);
        } else {
            outputError("Could not find valid source file for object (" + *itIt + ")");
            return false;
        }
    }
    return true;
}<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (testabilitydriver@nokia.com)
**
** This file is part of Testability Driver Qt Agent
**
** If you have questions regarding the use of this file, please contact
** Nokia at testabilitydriver@nokia.com .
**
** This library is free software; you can redistribute it and/or
** modify it 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.
**
****************************************************************************/

#include <QDebug>
#include <QProcess>
#include <QCoreApplication>

#include <taslogger.h>
#include <tascoreutils.h>
#include <tasdatashare.h>

#include "tasdeviceutils.h"
#include "tasclientmanager.h"

#include "startappservice.h"

#if (defined(Q_OS_WIN32) || defined(Q_OS_WINCE))
#include <windows.h>

#elif (defined(Q_OS_UNIX) || defined(Q_OS_WS_MAC))
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <QSharedMemory>
#endif

const char* const SET_PARAMS_ONLY = "set_params_only";
const char* const DETACH_MODE = "detached";
const char* const NO_WAIT = "noWait";

StartAppService::StartAppService()
{}

StartAppService::~StartAppService()
{}

bool StartAppService::executeService(TasCommandModel& model, TasResponse& response)
{
    if(model.service() == serviceName() ){
        // Turn screen on.
        TasDeviceUtils::resetInactivity();

        TasCommand* command = getCommandParameters(model, "Run");
        if(command){
            startApplication(*command, response);
        }
        else{
            TasLogger::logger()->error("StartAppService::executeService no Run command found!");
            response.setErrorMessage("Could not parse Run command from the request!");
        }
        return true;
    }
    else{
        return false;
    }
}

/*!
  Attempts to start a process using the application path send in the command model.
 */
void StartAppService::startApplication(TasCommand& command, TasResponse& response)
{
    QString applicationPath = command.parameter("application_path");
    QString args = command.parameter("arguments");
    QString envs = command.parameter("environment");
    TasLogger::logger()->debug(QString("TasServer::startApplication: '%1'").arg(applicationPath));
    TasLogger::logger()->debug(QString("TasServer::startApplication: Arguments: '%1'").arg(args));
    TasLogger::logger()->debug(QString("TasServer::startApplication: Environment: '%1'").arg(envs));
    QStringList arguments = args.split(",");
    QStringList environmentVars = envs.split(" ");

    setRuntimeParams(command);

    if(arguments.contains(SET_PARAMS_ONLY)){
        // do not start app, just need to set the parameters
        response.requester()->sendResponse(response.messageId(), QString("0"));
    }
    else{
        arguments.removeAll(DETACH_MODE);
        arguments.removeAll(NO_WAIT);
        launchDetached(applicationPath, arguments, environmentVars, response);
    }
}

void StartAppService::setRuntimeParams(TasCommand& command)
{
    QString applicationPath = command.parameter("application_path");
    QString eventList = command.parameter("events_to_listen");
    QString signalList = command.parameter("signals_to_listen");
    TasLogger::logger()->debug("StartAppService::setRuntimeParams signals: " + signalList);
    if(!eventList.isEmpty() || !signalList.isEmpty()){
        TasSharedData startupData(eventList.split(","), signalList.split(","));
        QString identifier = TasCoreUtils::parseExecutable(applicationPath);
        if(!TasClientManager::instance()->writeStartupData(identifier, startupData)){
            TasLogger::logger()->error("StartAppService::setRuntimeParams could not set run time params for identifier: " + identifier + "!");
        }
        else {
            TasLogger::logger()->error("StartAppService::setRuntimeParams set with identifier: " + identifier);
        }
    }
}

QHash<QString, QString> StartAppService::parseEnvironmentVariables(const QString& env) {
    QHash<QString,QString> vars;
    QStringList var = env.split(" ");
    foreach(QString str, var) {
        QStringList key = str.split("=");
        if (key.size() == 2) {
            vars[key.at(0)] = key.at(1);
        }
    }
    return vars;
}

#ifdef Q_OS_SYMBIAN
//Qt startDetach seems to leak memory so need to do it for now.
//to be removed when fix in qt
static void qt_create_symbian_commandline(
    const QStringList &arguments, const QString &nativeArguments, QString &commandLine)
{
    for (int i = 0; i < arguments.size(); ++i) {
        QString tmp = arguments.at(i);
        tmp.replace(QLatin1String("\\\""), QLatin1String("\\\\\""));
        tmp.replace(QLatin1String("\""), QLatin1String("\\\""));
        if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) {
            QString endQuote(QLatin1String("\""));
            int i = tmp.length();
            while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\')) {
                --i;
                endQuote += QLatin1String("\\");
            }
            commandLine += QLatin1String("\"") + tmp.left(i) + endQuote + QLatin1Char(' ');
        } else {
            commandLine += tmp + QLatin1Char(' ');
        }
    }

    if (!nativeArguments.isEmpty())
        commandLine += nativeArguments;
    else if (!commandLine.isEmpty()) // Chop the extra trailing space if any arguments were appended
        commandLine.chop(1);
}
#endif

void StartAppService::launchDetached(const QString& applicationPath, const QStringList& arguments, const QStringList& environmentVars, TasResponse& response)
{

#ifdef Q_OS_SYMBIAN
//Qt startDetach seems to leak memory so need to do it for now.
//to be removed when fix in qt
    qint64 pid;
    QString commandLine;
    QString nativeArguments;
    qt_create_symbian_commandline(arguments, nativeArguments, commandLine);
    TPtrC program_ptr(reinterpret_cast<const TText*>(applicationPath.constData()));
    TPtrC cmdline_ptr(reinterpret_cast<const TText*>(commandLine.constData()));
    RProcess process;
    if( process.Create(program_ptr, cmdline_ptr) == KErrNone){
        process.Resume();
        pid = process.Id().Id();
        process.Close();
        TasClientManager::instance()->addStartedApp(applicationPath, QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
        response.setData(QString::number(pid));
    }
#elif (defined(Q_OS_WIN32) || defined(Q_OS_WINCE))

    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    // Arguments
    QString argv = applicationPath + " " + arguments.join(" ");

    // Environment bloc variable
    QStringList envList = QProcess::systemEnvironment() << environmentVars;

	WCHAR* envp = (WCHAR*)malloc((envList.join(" ").length() + 2) * sizeof(WCHAR)); // just counting memory in cluding the NULL (\0) string ends and binal NULL block end
    LPTSTR env = (LPTSTR) envp;

    for (int i = 0; i < envList.length(); i++)
    {
        env = lstrcpy( env, (LPTSTR) envList[i].utf16() );
        env += lstrlen( (LPTSTR) envList[i].utf16() ) +1;
    }
    *env = (WCHAR) NULL;

    // DEBUG
//    LPTSTR lpszVariable = envp;
//    while (*lpszVariable) //while not null
//    {
//        TasLogger::logger()->debug( QString("TasServer::launchDetached: ENV: %1").arg(QString::fromUtf16((ushort *) lpszVariable)) );
//        lpszVariable += lstrlen(lpszVariable) + 1;
//    }

    // Start the child process.
    if( CreateProcess( NULL,   // No module name (use command line)
        (WCHAR *) argv.utf16(),           // Command line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        FALSE,          // Set handle inheritance to FALSE
        CREATE_UNICODE_ENVIRONMENT,              // 0 for no creation flags
        (LPVOID) envp,           // Use parent's environment block
        NULL,           // Use parent's starting directory
        &si,            // Pointer to STARTUPINFO structure
        &pi )           // Pointer to PROCESS_INFORMATION structure
    )
    {
        QString pid = QString::number(pi.dwProcessId);
        CloseHandle( pi.hProcess );
        CloseHandle( pi.hThread );
        TasLogger::logger()->debug( QString("TasServer::launchDetached: Child PID: %1").arg(pid) );
        response.setData(pid);

    }

#elif (defined(Q_OS_UNIX) || defined(Q_OS_WS_MAC))

    pid_t pid, sid, grandpid;

    /////int pidPipeDesc[2];
    /////qt_safe_pipe(pidPipeDesc);
    // Using shared memory pro IPC instead of qt pipes to avoid using private qt libraries.
    QSharedMemory mem("pid_mem");
    if ( !mem.create(sizeof(pid_t)) )
    {
        TasLogger::logger()->debug(QString("TasServer::startApplication: SharedMem ERROR: ").arg(mem.errorString()));
    }
    mem.lock();
    pid_t *mem_ptr = (pid_t *) mem.data();
    *mem_ptr = 0;
    mem.unlock();

    // Create Arguments ARRAY (application path to executable on first element)
    QStringList paramList;
    paramList << applicationPath;
    paramList << arguments;
    char **paramListArray = new char*[ paramList.length() + 1 ];
    for( int i = 0; i < paramList.length(); i++)
    {
        QByteArray variable = ((QString) paramList[i]).toLocal8Bit();
        char *const variablePtr = new char[variable.length() + 1];
        strcpy(variablePtr, variable.data());
        paramListArray[i] = variablePtr;
    }
     paramListArray[paramList.length()] = NULL;

    // Create environment Array with NULL end element
    QStringList envList = QProcess::systemEnvironment() << environmentVars;
    //TasLogger::logger()->debug(QString("TasServer::startApplipidPipeDesccation: ALL '%1'").arg(envList.join(",")));
    //TasLogger::logger()->debug(QString("TasServer::startApplication: USER '%1'").arg(environmentVars.join(",")));

    char **envListArray = new char*[ envList.length() + 1 ];
    for( int i = 0; i < envList.length(); i++)
    {
        QByteArray variable = ((QString) envList[i]).toLocal8Bit();
        char *const variablePtr = new char[variable.length() + 1];
        strcpy(variablePtr, variable.data());
        envListArray[i] = variablePtr;
    }
    envListArray[envList.length()] = NULL;

    // START MAKING CHILDREN HERE :D
    // Child
    if ( (pid = fork()) == 0) {

        // We are only going to write on the pipe for papa
        /////qt_safe_close(pidPipeDesc[0]);

        // Create new session for the process (detatch from parent process group)
        sid = setsid();
        if ( sid < 0 )
        {
            TasLogger::logger()->error( QString("TasServer::launchDetached:Failed to detach child."));
            exit(1);
        }

        // Grandchild
        if ( ( grandpid = fork() ) == 0 )
        {
            // detach ont he grandchild.
            mem.detach();

            // Try see if we don't need path
            execve( paramListArray[0], paramListArray, envListArray);

            // Try also on all path directories if above fails
            const QString path = QString::fromLocal8Bit(::getenv("PATH"));
            const QString file = QString::fromLocal8Bit(paramListArray[0]);
            if (!path.isEmpty())
            {
                QStringList pathEntries = path.split(QLatin1Char(':'));
                for (int k = 0; k < pathEntries.size(); ++k) {
                    QByteArray tmp = QFile::encodeName(pathEntries.at(k));
                    if (!tmp.endsWith('/')) tmp += '/';
                    tmp += QFile::encodeName(file);
                    paramListArray[0] = tmp.data();
                    TasLogger::logger()->error( QString("TasServer::launchDetached: PATH = '%1'").arg((char *) paramListArray[0]));
                    execve( paramListArray[0], paramListArray, envListArray);

                }
             }

            TasLogger::logger()->error( QString("TasServer::launchDetached: Granhild process died straight away."));
        }

        // Child exit in order to end detachment of grandchild
        else if( grandpid > 0)
        {
            /////qt_safe_write(pidPipeDesc[1], &grandpid, sizeof(pid_t));
            /////qt_safe_close(pidPipeDesc[1]);
            QSharedMemory mem("pid_mem");
            mem.attach();
            mem.lock();
            pid_t *mem_ptr = (pid_t *) mem.data();
            *mem_ptr = grandpid;
            mem.unlock();
            mem.detach();
            _exit(0);
        }
        else
        {
            // if child fork fails detach mem and kill child
            // TODO Return with error?
            mem.detach();
            _exit(0);
        }

    }

    // Parent
    else if (pid > 0) {

        // We are only going to read from the pipe from child
        /////qt_safe_close(pidPipeDesc[1]);
        pid_t actualpid = 0;
        /////qt_safe_read(pidPipeDesc[0], &actualpid, sizeof(pid_t));
        /////qt_safe_close(pidPipeDesc[0]);
        while(!actualpid)
        {
            mem.lock();
            pid_t *mem_ptr = (pid_t *) mem.data();
            actualpid = *mem_ptr;
            mem.unlock();
            TasLogger::logger()->debug( QString("TasServer::launchDetached: ACTUAL Child PID: %1").arg((int)actualpid) );
            //TODO? add counter to break free if error on fork()
        }
        mem.detach();

        pid = actualpid;

        // Free memory
        for (int i = 0; i < paramList.length(); i++ )
        {
            delete [] paramListArray[i];
        }
        delete [] paramListArray;

        for (int i = 0; i < envList.length(); i++ )
        {
            delete [] envListArray[i];
        }
        delete [] envListArray;

        TasLogger::logger()->debug( QString("TasServer::launchDetached: Child PID: %1").arg((int)pid) );
        response.setData(QString::number((int) pid));
    }

#else
    qint64 pid;
    if(QProcess::startDetached(applicationPath, arguments, ".", &pid)){

	    TasClientManager::instance()->addStartedApp(applicationPath, QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
        response.setData(QString::number(pid));
    }
#endif
    else{
#if (defined(Q_OS_UNIX) || defined(Q_OS_WS_MAC)) && !defined(Q_OS_SYMBIAN)
        // if parent fork fails, clear mem and send error
        mem.detach();
#endif
        TasLogger::logger()->error("TasServer::launchDetached: Could not start the application " + applicationPath);
        response.setErrorMessage("Could not start the application " + applicationPath);
    }
#if (defined(Q_OS_WIN32) || defined(Q_OS_WINCE))
	free(envp);
#endif
}

<commit_msg>Modified error handling on startappservice for linux<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (testabilitydriver@nokia.com)
**
** This file is part of Testability Driver Qt Agent
**
** If you have questions regarding the use of this file, please contact
** Nokia at testabilitydriver@nokia.com .
**
** This library is free software; you can redistribute it and/or
** modify it 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.
**
****************************************************************************/

#include <QDebug>
#include <QProcess>
#include <QCoreApplication>

#include <taslogger.h>
#include <tascoreutils.h>
#include <tasdatashare.h>

#include "tasdeviceutils.h"
#include "tasclientmanager.h"

#include "startappservice.h"

#if (defined(Q_OS_WIN32) || defined(Q_OS_WINCE))
#include <windows.h>

#elif (defined(Q_OS_UNIX) || defined(Q_OS_WS_MAC))
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <QSharedMemory>
#endif

const char* const SET_PARAMS_ONLY = "set_params_only";
const char* const DETACH_MODE = "detached";
const char* const NO_WAIT = "noWait";

StartAppService::StartAppService()
{}

StartAppService::~StartAppService()
{}

bool StartAppService::executeService(TasCommandModel& model, TasResponse& response)
{
    if(model.service() == serviceName() ){
        // Turn screen on.
        TasDeviceUtils::resetInactivity();

        TasCommand* command = getCommandParameters(model, "Run");
        if(command){
            startApplication(*command, response);
        }
        else{
            TasLogger::logger()->error("StartAppService::executeService no Run command found!");
            response.setErrorMessage("Could not parse Run command from the request!");
        }
        return true;
    }
    else{
        return false;
    }
}

/*!
  Attempts to start a process using the application path send in the command model.
 */
void StartAppService::startApplication(TasCommand& command, TasResponse& response)
{
    QString applicationPath = command.parameter("application_path");
    QString args = command.parameter("arguments");
    QString envs = command.parameter("environment");
    TasLogger::logger()->debug(QString("TasServer::startApplication: '%1'").arg(applicationPath));
    TasLogger::logger()->debug(QString("TasServer::startApplication: Arguments: '%1'").arg(args));
    TasLogger::logger()->debug(QString("TasServer::startApplication: Environment: '%1'").arg(envs));
    QStringList arguments = args.split(",");
    QStringList environmentVars = envs.split(" ");

    setRuntimeParams(command);

    if(arguments.contains(SET_PARAMS_ONLY)){
        // do not start app, just need to set the parameters
        response.requester()->sendResponse(response.messageId(), QString("0"));
    }
    else{
        arguments.removeAll(DETACH_MODE);
        arguments.removeAll(NO_WAIT);
        launchDetached(applicationPath, arguments, environmentVars, response);
    }
}

void StartAppService::setRuntimeParams(TasCommand& command)
{
    QString applicationPath = command.parameter("application_path");
    QString eventList = command.parameter("events_to_listen");
    QString signalList = command.parameter("signals_to_listen");
    TasLogger::logger()->debug("StartAppService::setRuntimeParams signals: " + signalList);
    if(!eventList.isEmpty() || !signalList.isEmpty()){
        TasSharedData startupData(eventList.split(","), signalList.split(","));
        QString identifier = TasCoreUtils::parseExecutable(applicationPath);
        if(!TasClientManager::instance()->writeStartupData(identifier, startupData)){
            TasLogger::logger()->error("StartAppService::setRuntimeParams could not set run time params for identifier: " + identifier + "!");
        }
        else {
            TasLogger::logger()->error("StartAppService::setRuntimeParams set with identifier: " + identifier);
        }
    }
}

QHash<QString, QString> StartAppService::parseEnvironmentVariables(const QString& env) {
    QHash<QString,QString> vars;
    QStringList var = env.split(" ");
    foreach(QString str, var) {
        QStringList key = str.split("=");
        if (key.size() == 2) {
            vars[key.at(0)] = key.at(1);
        }
    }
    return vars;
}

#ifdef Q_OS_SYMBIAN
//Qt startDetach seems to leak memory so need to do it for now.
//to be removed when fix in qt
static void qt_create_symbian_commandline(
    const QStringList &arguments, const QString &nativeArguments, QString &commandLine)
{
    for (int i = 0; i < arguments.size(); ++i) {
        QString tmp = arguments.at(i);
        tmp.replace(QLatin1String("\\\""), QLatin1String("\\\\\""));
        tmp.replace(QLatin1String("\""), QLatin1String("\\\""));
        if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) {
            QString endQuote(QLatin1String("\""));
            int i = tmp.length();
            while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\')) {
                --i;
                endQuote += QLatin1String("\\");
            }
            commandLine += QLatin1String("\"") + tmp.left(i) + endQuote + QLatin1Char(' ');
        } else {
            commandLine += tmp + QLatin1Char(' ');
        }
    }

    if (!nativeArguments.isEmpty())
        commandLine += nativeArguments;
    else if (!commandLine.isEmpty()) // Chop the extra trailing space if any arguments were appended
        commandLine.chop(1);
}
#endif

void StartAppService::launchDetached(const QString& applicationPath, const QStringList& arguments, const QStringList& environmentVars, TasResponse& response)
{

#ifdef Q_OS_SYMBIAN
//Qt startDetach seems to leak memory so need to do it for now.
//to be removed when fix in qt
    qint64 pid;
    QString commandLine;
    QString nativeArguments;
    qt_create_symbian_commandline(arguments, nativeArguments, commandLine);
    TPtrC program_ptr(reinterpret_cast<const TText*>(applicationPath.constData()));
    TPtrC cmdline_ptr(reinterpret_cast<const TText*>(commandLine.constData()));
    RProcess process;
    if( process.Create(program_ptr, cmdline_ptr) == KErrNone){
        process.Resume();
        pid = process.Id().Id();
        process.Close();
        TasClientManager::instance()->addStartedApp(applicationPath, QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
        response.setData(QString::number(pid));
    }
#elif (defined(Q_OS_WIN32) || defined(Q_OS_WINCE))

    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    // Arguments
    QString argv = applicationPath + " " + arguments.join(" ");

    // Environment bloc variable
    QStringList envList = QProcess::systemEnvironment() << environmentVars;

    WCHAR* envp = (WCHAR*)malloc((envList.join(" ").length() + 2) * sizeof(WCHAR)); // just counting memory in cluding the NULL (\0) string ends and binal NULL block end
    LPTSTR env = (LPTSTR) envp;

    for (int i = 0; i < envList.length(); i++)
    {
        env = lstrcpy( env, (LPTSTR) envList[i].utf16() );
        env += lstrlen( (LPTSTR) envList[i].utf16() ) +1;
    }
    *env = (WCHAR) NULL;

    // DEBUG
//    LPTSTR lpszVariable = envp;
//    while (*lpszVariable) //while not null
//    {
//        TasLogger::logger()->debug( QString("TasServer::launchDetached: ENV: %1").arg(QString::fromUtf16((ushort *) lpszVariable)) );
//        lpszVariable += lstrlen(lpszVariable) + 1;
//    }

    // Start the child process.
    if( CreateProcess( NULL,   // No module name (use command line)
        (WCHAR *) argv.utf16(),           // Command line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        FALSE,          // Set handle inheritance to FALSE
        CREATE_UNICODE_ENVIRONMENT,              // 0 for no creation flags
        (LPVOID) envp,           // Use parent's environment block
        NULL,           // Use parent's starting directory
        &si,            // Pointer to STARTUPINFO structure
        &pi )           // Pointer to PROCESS_INFORMATION structure
    )
    {
        QString pid = QString::number(pi.dwProcessId);
        CloseHandle( pi.hProcess );
        CloseHandle( pi.hThread );
        TasLogger::logger()->debug( QString("TasServer::launchDetached: Child PID: %1").arg(pid) );
        response.setData(pid);

    }

#elif (defined(Q_OS_UNIX) || defined(Q_OS_WS_MAC))

    pid_t pid, sid, grandpid;

    // Create Arguments ARRAY (application path to executable on first element)
    QStringList paramList;
    paramList << applicationPath;
    paramList << arguments;
    char **paramListArray = new char*[ paramList.length() + 1 ];
    for( int i = 0; i < paramList.length(); i++)
    {
        QByteArray variable = ((QString) paramList[i]).toLocal8Bit();
        char *const variablePtr = new char[variable.length() + 1];
        strcpy(variablePtr, variable.data());
        paramListArray[i] = variablePtr;
    }
     paramListArray[paramList.length()] = NULL;

    // Create environment Array with NULL end element
    QStringList envList = QProcess::systemEnvironment() << environmentVars;
    char **envListArray = new char*[ envList.length() + 1 ];
    for( int i = 0; i < envList.length(); i++)
    {
        QByteArray variable = ((QString) envList[i]).toLocal8Bit();
        char *const variablePtr = new char[variable.length() + 1];
        strcpy(variablePtr, variable.data());
        envListArray[i] = variablePtr;
    }
    envListArray[envList.length()] = NULL;

    /////int pidPipeDesc[2];
    /////qt_safe_pipe(pidPipeDesc);
    // Using shared memory pro IPC instead of qt pipes to avoid using private qt libraries.
    QSharedMemory mem("pid_mem");
    if ( mem.create(sizeof(pid_t)) )
    {

        mem.lock();
        pid_t *mem_ptr = (pid_t *) mem.data();
        *mem_ptr = 0;
        mem.unlock();

        // START MAKING CHILDREN HERE :D
        // Child
        if ( (pid = fork()) == 0) {

            // We are only going to write on the pipe for papa
            /////qt_safe_close(pidPipeDesc[0]);

            // Create new session for the process (detatch from parent process group)
            sid = setsid();
            if ( sid < 0 )
            {
                TasLogger::logger()->error( QString("TasServer::launchDetached:Failed to detach child."));
                exit(1);
            }

            // Grandchild
            if ( ( grandpid = fork() ) == 0 )
            {
                // detach ont he grandchild.
                mem.detach();

                // Try see if we don't need path
                execve( paramListArray[0], paramListArray, envListArray);

                // Try also on all path directories if above fails
                const QString path = QString::fromLocal8Bit(::getenv("PATH"));
                const QString file = QString::fromLocal8Bit(paramListArray[0]);
                if (!path.isEmpty())
                {
                    QStringList pathEntries = path.split(QLatin1Char(':'));
                    for (int k = 0; k < pathEntries.size(); ++k) {
                        QByteArray tmp = QFile::encodeName(pathEntries.at(k));
                        if (!tmp.endsWith('/')) tmp += '/';
                        tmp += QFile::encodeName(file);
                        paramListArray[0] = tmp.data();
                        TasLogger::logger()->error( QString("TasServer::launchDetached: PATH = '%1'").arg((char *) paramListArray[0]));
                        execve( paramListArray[0], paramListArray, envListArray);

                    }
                 }

                TasLogger::logger()->error( QString("TasServer::launchDetached: Granhild process died straight away."));
            }

            // Child exit in order to end detachment of grandchild
            else if( grandpid > 0)
            {
                /////qt_safe_write(pidPipeDesc[1], &grandpid, sizeof(pid_t));
                /////qt_safe_close(pidPipeDesc[1]);
                QSharedMemory mem("pid_mem");
                mem.attach();
                mem.lock();
                pid_t *mem_ptr = (pid_t *) mem.data();
                *mem_ptr = grandpid;
                mem.unlock();
                mem.detach();
                _exit(0);
            }
            else
            {
                // if child fork fails detach mem and kill child
                // TODO Return with error?
                mem.detach();
                _exit(0);
            }

        }

        // Parent
        else if (pid > 0) {

            // We are only going to read from the pipe from child
            /////qt_safe_close(pidPipeDesc[1]);
            pid_t actualpid = 0;
            /////qt_safe_read(pidPipeDesc[0], &actualpid, sizeof(pid_t));
            /////qt_safe_close(pidPipeDesc[0]);
            while(!actualpid)
            {
                mem.lock();
                pid_t *mem_ptr = (pid_t *) mem.data();
                actualpid = *mem_ptr;
                mem.unlock();
                TasLogger::logger()->debug( QString("TasServer::launchDetached: ACTUAL Child PID: %1").arg((int)actualpid) );
                //TODO? add counter to break free if error on fork()
            }
            mem.detach();

            pid = actualpid;

            // Free memory
            for (int i = 0; i < paramList.length(); i++ )
            {
                delete [] paramListArray[i];
            }
            delete [] paramListArray;

            for (int i = 0; i < envList.length(); i++ )
            {
                delete [] envListArray[i];
            }
            delete [] envListArray;

            TasLogger::logger()->debug( QString("TasServer::launchDetached: Child PID: %1").arg((int)pid) );
            response.setData(QString::number((int) pid));
        }
        else
        {
            //fails, clear mem and send error
            mem.detach();
            TasLogger::logger()->error("TasServer::launchDetached: Could not start the application " + applicationPath);
            response.setErrorMessage("Could not start the application " + applicationPath);

        }
    }

#else
    qint64 pid;
    if(QProcess::startDetached(applicationPath, arguments, ".", &pid)){

	    TasClientManager::instance()->addStartedApp(applicationPath, QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
        response.setData(QString::number(pid));
    }
#endif
    else{
#if (defined(Q_OS_UNIX) || defined(Q_OS_WS_MAC)) && !defined(Q_OS_SYMBIAN)
        // if parent fork fails, clear mem and send error
        mem.detach();
        TasLogger::logger()->debug(QString("TasServer::startApplication: SharedMem ERROR: ").arg(mem.errorString()));
#endif
        TasLogger::logger()->error("TasServer::launchDetached: Could not start the application " + applicationPath);
        response.setErrorMessage("Could not start the application " + applicationPath);
    }
#if (defined(Q_OS_WIN32) || defined(Q_OS_WINCE))
	free(envp);
#endif
}

<|endoftext|>


<commit_before>/**
 * light_scan_sim test_ray_cast.cpp
 * @brief Test simulating laser rays on an image.
 *
 * @copyright 2017 Joseph Duchesne
 * @author Joseph Duchesne
 */

#include "light_scan_sim/ray_cast.h"
#include <gtest/gtest.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

// The fixture for testing class RayCast
class RayCastTest : public ::testing::Test {};

TEST_F(RayCastTest, TestTest) {
  RayCast rc;
  cv::Point start, end, hit;

  // Set up the raycast with a very simple map
  cv::Mat mat = cv::Mat::zeros(20, 20, CV_8UC1);
  cv::rectangle( mat, cv::Point( 10, 0 ), cv::Point( 20, 20), 255, CV_FILLED);
  rc.SetMap(mat, 1.0);

  // Test tracing from empty space into wall
  start = cv::Point(5,5);
  end = cv::Point(15,5);
  EXPECT_TRUE(rc.Trace(start, end, hit));
  EXPECT_NEAR(hit.x, 10, 1e-5);
  EXPECT_NEAR(hit.y, 5, 1e-5);

  // Test tracing out of map into empty space
  start = cv::Point(5,5);
  end = cv::Point(-5,5);
  EXPECT_FALSE(rc.Trace(start, end, hit));
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>added RayCast.Scan unit test<commit_after>/**
 * light_scan_sim test_ray_cast.cpp
 * @brief Test simulating laser rays on an image.
 *
 * @copyright 2017 Joseph Duchesne
 * @author Joseph Duchesne
 */

#include "light_scan_sim/ray_cast.h"
#include <gtest/gtest.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <sensor_msgs/LaserScan.h>

// The fixture for testing class RayCast
class RayCastTest : public ::testing::Test {};

TEST_F(RayCastTest, TraceTest) {
  RayCast rc;
  cv::Point start, end, hit;

  // Set up the raycast with a very simple map
  cv::Mat mat = cv::Mat::zeros(20, 20, CV_8UC1);
  cv::rectangle( mat, cv::Point( 10, 0 ), cv::Point( 20, 20), 255, CV_FILLED);
  rc.SetMap(mat, 1.0);

  // Test tracing from empty space into wall
  start = cv::Point(5,5);
  end = cv::Point(15,5);
  EXPECT_TRUE(rc.Trace(start, end, hit));
  EXPECT_NEAR(hit.x, 10, 1e-5);
  EXPECT_NEAR(hit.y, 5, 1e-5);

  // Test tracing out of map into empty space
  start = cv::Point(5,5);
  end = cv::Point(-5,5);
  EXPECT_FALSE(rc.Trace(start, end, hit));
}

TEST_F(RayCastTest, ScanTest) {
  RayCast rc(0, 50, -M_PI_2, M_PI_2, M_PI_2, 0);
  cv::Point start(5,5);

  // Set up the raycast with a very simple map
  cv::Mat mat = cv::Mat::zeros(20, 20, CV_8UC1);
  cv::rectangle( mat, cv::Point( 15, 0 ), cv::Point( 20, 20), 255, CV_FILLED);
  cv::rectangle( mat, cv::Point( 0, 17 ), cv::Point( 20, 20), 255, CV_FILLED);
  rc.SetMap(mat, 2.0);  // 2.0m per pixel

  // Test tracing from empty space into wall
  sensor_msgs::LaserScan s = rc.Scan(start, M_PI_2);  // Scan angled up

  // General properties
  EXPECT_NEAR(s.angle_min, -M_PI_2, 1e-5);
  EXPECT_EQ(3, s.ranges.size());

  // Right wall
  EXPECT_NEAR(s.ranges[0], 20.0, 1e-5);  // 20m to right wall
  EXPECT_NEAR(s.ranges[1], 24.0, 1e-5);  // 24m to top wall
  EXPECT_NEAR(s.ranges[2], 51.0, 1e-5);  // max range + 1m for no return
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <istream>
#include <sstream>

#include "parsers/parse_error.hh"
#include "parsers/tina.hh"
#include "pn/arc.hh"

namespace pnmc { namespace parsers {

/*------------------------------------------------------------------------------------------------*/

/*------------------------------------------------------------------------------------------------*/

std::pair<std::string, unsigned int>
place_valuation(const std::string& s)
{
  const auto star_cit = std::find(s.cbegin(), s.cend(), '*');
  if (star_cit == s.cend())
  {
    return std::make_pair(s, 1);
  }
  try
  {
    const auto valuation = std::stoi(std::string(star_cit + 1, s.cend()));
    return std::make_pair(std::string(s.cbegin(), star_cit), valuation);
  }
  catch (const std::invalid_argument&)
  {
    throw parse_error("Valuation '" + std::string(star_cit + 1, s.cend()) + "' is not a value");
  }
}

/*------------------------------------------------------------------------------------------------*/

unsigned int
marking(const std::string& s)
{
  if (*s.cbegin() == '(' and *std::prev(s.cend()) == ')')
  {
    try
    {
      return std::stoi(std::string(std::next(s.cbegin()), std::prev(s.cend())));
    }
    catch (const std::invalid_argument&)
    {
      throw parse_error( "Marking '" + std::string(std::next(s.cbegin()), std::prev(s.cend()))
                       + "' is not a value");
    }
  }
  else
  {
    throw parse_error("Invalid marking format: " + s);
  }
}

/*------------------------------------------------------------------------------------------------*/

std::shared_ptr<pn::net>
tina(std::istream& in)
{
  std::shared_ptr<pn::net> net_ptr = std::make_shared<pn::net>();
  auto& net = *net_ptr;

  try
  {
    std::string line, s0, s1, s2;
    line.reserve(1024);

    while (std::getline(in, line))
    {
      std::istringstream ss(line);

      // Empty line or comment.
      if (((ss >> std::ws).peek() == '#') or not (ss >> s0))
      {
        continue;
      }

      // Net
      if (s0 == "net")
      {
        continue;
      }

      // Transitions
      else if (s0 == "tr")
      {
        std::string place_id;
        unsigned int valuation;

        if (ss >> s0)
        {
          net.add_transition(s0, "");
        }
        else
        {
          throw parse_error("Invalid transition: " + line);
        }

        // Skip time interval, if any.
        const auto c = (ss >> std::ws).peek();
        if (c == '[' or c == ']')
        {
          ss >> s1;
        }

        while (ss >> s1)
        {
          if (s1 == "->")
          {
            break;
          }
          std::tie(place_id, valuation) = place_valuation(s1);
          net.add_pre_place(s0, place_id, pn::arc(valuation));
        }

        while (ss >> s1)
        {
          std::tie(place_id, valuation) = place_valuation(s1);
          net.add_post_place(s0, place_id, pn::arc(valuation));
        }
      }

      // Places
      else if (s0 == "pl")
      {
        if (ss >> s1 >> s2)
        {
          net.add_place(s1, "", marking(s2));
        }
        else
        {
          throw parse_error("Invalid place: " + line);
        }
      }

      // Error.
      else
      {
        throw parse_error("Invalid line: " + line);
      }
    }
  }
  catch (const parse_error& p)
  {
    std::cerr << p.what() << std::endl;
    return nullptr;
  }

  return net_ptr;
}

/*------------------------------------------------------------------------------------------------*/

}} // namespace pnmc::parsers
<commit_msg>Check that ‘->’ is present in a TINA transition.<commit_after>#include <algorithm>
#include <istream>
#include <sstream>

#include "parsers/parse_error.hh"
#include "parsers/tina.hh"
#include "pn/arc.hh"

namespace pnmc { namespace parsers {

/*------------------------------------------------------------------------------------------------*/

/*------------------------------------------------------------------------------------------------*/

std::pair<std::string, unsigned int>
place_valuation(const std::string& s)
{
  const auto star_cit = std::find(s.cbegin(), s.cend(), '*');
  if (star_cit == s.cend())
  {
    return std::make_pair(s, 1);
  }
  try
  {
    const auto valuation = std::stoi(std::string(star_cit + 1, s.cend()));
    return std::make_pair(std::string(s.cbegin(), star_cit), valuation);
  }
  catch (const std::invalid_argument&)
  {
    throw parse_error("Valuation '" + std::string(star_cit + 1, s.cend()) + "' is not a value");
  }
}

/*------------------------------------------------------------------------------------------------*/

unsigned int
marking(const std::string& s)
{
  if (*s.cbegin() == '(' and *std::prev(s.cend()) == ')')
  {
    try
    {
      return std::stoi(std::string(std::next(s.cbegin()), std::prev(s.cend())));
    }
    catch (const std::invalid_argument&)
    {
      throw parse_error( "Marking '" + std::string(std::next(s.cbegin()), std::prev(s.cend()))
                       + "' is not a value");
    }
  }
  else
  {
    throw parse_error("Invalid marking format: " + s);
  }
}

/*------------------------------------------------------------------------------------------------*/

std::shared_ptr<pn::net>
tina(std::istream& in)
{
  std::shared_ptr<pn::net> net_ptr = std::make_shared<pn::net>();
  auto& net = *net_ptr;

  try
  {
    std::string line, s0, s1, s2;
    line.reserve(1024);

    while (std::getline(in, line))
    {
      std::istringstream ss(line);

      // Empty line or comment.
      if (((ss >> std::ws).peek() == '#') or not (ss >> s0))
      {
        continue;
      }

      // Net
      if (s0 == "net")
      {
        continue;
      }

      // Transitions
      else if (s0 == "tr")
      {
        std::string place_id;
        unsigned int valuation;

        if (ss >> s0)
        {
          net.add_transition(s0, "");
        }
        else
        {
          throw parse_error("Invalid transition: " + line);
        }

        // Skip time interval, if any.
        const auto c = (ss >> std::ws).peek();
        if (c == '[' or c == ']')
        {
          ss >> s1;
        }

        bool found_arrow = false;
        while (ss >> s1)
        {
          if (s1 == "->")
          {
            found_arrow = true;
            break;
          }
          std::tie(place_id, valuation) = place_valuation(s1);
          net.add_pre_place(s0, place_id, pn::arc(valuation));
        }

        if (not found_arrow)
        {
          throw parse_error("Invalid transition (missing '->'): " + line);
        }

        while (ss >> s1)
        {
          std::tie(place_id, valuation) = place_valuation(s1);
          net.add_post_place(s0, place_id, pn::arc(valuation));
        }
      }

      // Places
      else if (s0 == "pl")
      {
        if (ss >> s1 >> s2)
        {
          net.add_place(s1, "", marking(s2));
        }
        else
        {
          throw parse_error("Invalid place: " + line);
        }
      }

      // Error.
      else
      {
        throw parse_error("Invalid line: " + line);
      }
    }
  }
  catch (const parse_error& p)
  {
    std::cerr << p.what() << std::endl;
    return nullptr;
  }

  return net_ptr;
}

/*------------------------------------------------------------------------------------------------*/

}} // namespace pnmc::parsers
<|endoftext|>


<commit_before>#include "parsing/utf8.hpp"

#include <string>
#include <string.h>

#include "rdb_protocol/datum_string.hpp"

namespace utf8 {

static unsigned int HIGH_BIT = 0x80;
static unsigned int HIGH_TWO_BITS = 0xC0;
static unsigned int HIGH_THREE_BITS = 0xE0;
static unsigned int HIGH_FOUR_BITS = 0xF0;
static unsigned int HIGH_FIVE_BITS = 0xF8;

inline bool is_standalone(char c) {
    // 0xxxxxxx - ASCII character
    return (c & HIGH_BIT) == 0;
}

inline bool is_twobyte_start(char c) {
    // 110xxxxx - two character multibyte
    return (c & HIGH_THREE_BITS) == HIGH_TWO_BITS;
}

inline bool is_threebyte_start(char c) {
    // 1110xxxx - three character multibyte
    return (c & HIGH_FOUR_BITS) == HIGH_THREE_BITS;
}

inline bool is_fourbyte_start(char c) {
    // 11110xxx - four character multibyte
    return (c & HIGH_FIVE_BITS) == HIGH_FOUR_BITS;
}

inline bool is_continuation(char c) {
    // 10xxxxxx - continuation character
    return ((c & HIGH_TWO_BITS) == HIGH_BIT);
}

inline unsigned int extract_bits(char c, unsigned int bits) {
    return ((c & ~bits) & 0xFF);
}

inline unsigned int continuation_data(char c) {
    return extract_bits(c, HIGH_TWO_BITS);
}

inline unsigned int extract_and_shift(char c, unsigned int bits, unsigned int amount) {
    return extract_bits(c, bits) << amount;
}

template <class Iterator>
inline bool check_continuation(const Iterator &p, const Iterator &end,
                               size_t position, reason_t *reason) {
    if (p == end) {
        reason->position = position;
        reason->explanation = "Expected continuation byte, saw end of string";
        return false;
    }
    if (!is_continuation(*p)) {
        reason->position = position;
        reason->explanation = "Expected continuation byte, saw something else";
        return false;
    }
    return true;
}

template <class Iterator>
inline bool is_valid_internal(const Iterator &begin, const Iterator &end,
                              reason_t *reason) {
    Iterator p = begin;
    size_t position = 0;
    while (p != end) {
        if (is_standalone(*p)) {
            // 0xxxxxxx - ASCII character
            // don't need to do anything
        } else if (is_twobyte_start(*p)) {
            // 110xxxxx - two character multibyte
            unsigned int result = extract_and_shift(*p, HIGH_THREE_BITS, 6);
            ++p; ++position;
            if (!check_continuation(p, end, position, reason)) return false;
            result |= continuation_data(*p);
            if (result < 0x0080) {
                // can be represented in one byte, so using two is illegal
                reason->position = position;
                reason->explanation = "Overlong encoding seen";
                return false;
            }
        } else if (is_threebyte_start(*p)) {
            // 1110xxxx - three character multibyte
            unsigned int result = extract_and_shift(*p, HIGH_FOUR_BITS, 12);
            ++p; ++position;
            if (!check_continuation(p, end, position, reason)) return false;
            result |= continuation_data(*p) << 6;
            ++p; ++position;
            if (!check_continuation(p, end, position, reason)) return false;
            result |= continuation_data(*p);
            if (result < 0x0800) {
                // can be represented in two bytes, so using three is illegal
                reason->position = position;
                reason->explanation = "Overlong encoding seen";
                return false;
            }
        } else if (is_fourbyte_start(*p)) {
            // 11110xxx - four character multibyte
            unsigned int result = extract_and_shift(*p, HIGH_FIVE_BITS, 18);
            ++p; ++position;
            if (!check_continuation(p, end, position, reason)) return false;
            result |= continuation_data(*p) << 12;
            ++p; ++position;
            if (!check_continuation(p, end, position, reason)) return false;
            result |= continuation_data(*p) << 6;
            ++p; ++position;
            if (!check_continuation(p, end, position, reason)) return false;
            result |= continuation_data(*p);
            if (result < 0x10000) {
                // can be represented in three bytes, so using four is illegal
                reason->position = position;
                reason->explanation = "Overlong encoding seen";
                return false;
            }
            if (result > 0x10FFFF) {
                // UTF-8 defined by RFC 3629 to end at U+10FFFF now
                reason->position = position;
                reason->explanation = "Non-Unicode character encoded (beyond U+10FFFF)";
                return false;
            }
        } else {
            // high bit character outside of a surrogate context
            reason->position = position;
            reason->explanation = "Invalid initial byte seen";
            return false;
        }
        ++p; ++position;
    }
    return true;
}

bool is_valid(const datum_string_t &str) {
    reason_t reason;
    return is_valid_internal(str.data(), str.data() + str.size(), &reason);
}

bool is_valid(const std::string &str) {
    reason_t reason;
    return is_valid_internal(str.begin(), str.end(), &reason);
}

bool is_valid(const char *start, const char *end) {
    reason_t reason;
    return is_valid_internal(start, end, &reason);
}

bool is_valid(const char *str) {
    reason_t reason;
    size_t len = strlen(str);
    const char *end = str + len;
    return is_valid_internal(str, end, &reason);
}

bool is_valid(const datum_string_t &str, reason_t *reason) {
    return is_valid_internal(str.data(), str.data() + str.size(), reason);
}

bool is_valid(const std::string &str, reason_t *reason) {
    return is_valid_internal(str.begin(), str.end(), reason);
}

bool is_valid(const char *start, const char *end, reason_t *reason) {
    return is_valid_internal(start, end, reason);
}

bool is_valid(const char *str, reason_t *reason) {
    size_t len = strlen(str);
    const char *end = str + len;
    return is_valid_internal(str, end, reason);
}

};
<commit_msg>Add namespace comment.<commit_after>#include "parsing/utf8.hpp"

#include <string>
#include <string.h>

#include "rdb_protocol/datum_string.hpp"

namespace utf8 {

static unsigned int HIGH_BIT = 0x80;
static unsigned int HIGH_TWO_BITS = 0xC0;
static unsigned int HIGH_THREE_BITS = 0xE0;
static unsigned int HIGH_FOUR_BITS = 0xF0;
static unsigned int HIGH_FIVE_BITS = 0xF8;

inline bool is_standalone(char c) {
    // 0xxxxxxx - ASCII character
    return (c & HIGH_BIT) == 0;
}

inline bool is_twobyte_start(char c) {
    // 110xxxxx - two character multibyte
    return (c & HIGH_THREE_BITS) == HIGH_TWO_BITS;
}

inline bool is_threebyte_start(char c) {
    // 1110xxxx - three character multibyte
    return (c & HIGH_FOUR_BITS) == HIGH_THREE_BITS;
}

inline bool is_fourbyte_start(char c) {
    // 11110xxx - four character multibyte
    return (c & HIGH_FIVE_BITS) == HIGH_FOUR_BITS;
}

inline bool is_continuation(char c) {
    // 10xxxxxx - continuation character
    return ((c & HIGH_TWO_BITS) == HIGH_BIT);
}

inline unsigned int extract_bits(char c, unsigned int bits) {
    return ((c & ~bits) & 0xFF);
}

inline unsigned int continuation_data(char c) {
    return extract_bits(c, HIGH_TWO_BITS);
}

inline unsigned int extract_and_shift(char c, unsigned int bits, unsigned int amount) {
    return extract_bits(c, bits) << amount;
}

template <class Iterator>
inline bool check_continuation(const Iterator &p, const Iterator &end,
                               size_t position, reason_t *reason) {
    if (p == end) {
        reason->position = position;
        reason->explanation = "Expected continuation byte, saw end of string";
        return false;
    }
    if (!is_continuation(*p)) {
        reason->position = position;
        reason->explanation = "Expected continuation byte, saw something else";
        return false;
    }
    return true;
}

template <class Iterator>
inline bool is_valid_internal(const Iterator &begin, const Iterator &end,
                              reason_t *reason) {
    Iterator p = begin;
    size_t position = 0;
    while (p != end) {
        if (is_standalone(*p)) {
            // 0xxxxxxx - ASCII character
            // don't need to do anything
        } else if (is_twobyte_start(*p)) {
            // 110xxxxx - two character multibyte
            unsigned int result = extract_and_shift(*p, HIGH_THREE_BITS, 6);
            ++p; ++position;
            if (!check_continuation(p, end, position, reason)) return false;
            result |= continuation_data(*p);
            if (result < 0x0080) {
                // can be represented in one byte, so using two is illegal
                reason->position = position;
                reason->explanation = "Overlong encoding seen";
                return false;
            }
        } else if (is_threebyte_start(*p)) {
            // 1110xxxx - three character multibyte
            unsigned int result = extract_and_shift(*p, HIGH_FOUR_BITS, 12);
            ++p; ++position;
            if (!check_continuation(p, end, position, reason)) return false;
            result |= continuation_data(*p) << 6;
            ++p; ++position;
            if (!check_continuation(p, end, position, reason)) return false;
            result |= continuation_data(*p);
            if (result < 0x0800) {
                // can be represented in two bytes, so using three is illegal
                reason->position = position;
                reason->explanation = "Overlong encoding seen";
                return false;
            }
        } else if (is_fourbyte_start(*p)) {
            // 11110xxx - four character multibyte
            unsigned int result = extract_and_shift(*p, HIGH_FIVE_BITS, 18);
            ++p; ++position;
            if (!check_continuation(p, end, position, reason)) return false;
            result |= continuation_data(*p) << 12;
            ++p; ++position;
            if (!check_continuation(p, end, position, reason)) return false;
            result |= continuation_data(*p) << 6;
            ++p; ++position;
            if (!check_continuation(p, end, position, reason)) return false;
            result |= continuation_data(*p);
            if (result < 0x10000) {
                // can be represented in three bytes, so using four is illegal
                reason->position = position;
                reason->explanation = "Overlong encoding seen";
                return false;
            }
            if (result > 0x10FFFF) {
                // UTF-8 defined by RFC 3629 to end at U+10FFFF now
                reason->position = position;
                reason->explanation = "Non-Unicode character encoded (beyond U+10FFFF)";
                return false;
            }
        } else {
            // high bit character outside of a surrogate context
            reason->position = position;
            reason->explanation = "Invalid initial byte seen";
            return false;
        }
        ++p; ++position;
    }
    return true;
}

bool is_valid(const datum_string_t &str) {
    reason_t reason;
    return is_valid_internal(str.data(), str.data() + str.size(), &reason);
}

bool is_valid(const std::string &str) {
    reason_t reason;
    return is_valid_internal(str.begin(), str.end(), &reason);
}

bool is_valid(const char *start, const char *end) {
    reason_t reason;
    return is_valid_internal(start, end, &reason);
}

bool is_valid(const char *str) {
    reason_t reason;
    size_t len = strlen(str);
    const char *end = str + len;
    return is_valid_internal(str, end, &reason);
}

bool is_valid(const datum_string_t &str, reason_t *reason) {
    return is_valid_internal(str.data(), str.data() + str.size(), reason);
}

bool is_valid(const std::string &str, reason_t *reason) {
    return is_valid_internal(str.begin(), str.end(), reason);
}

bool is_valid(const char *start, const char *end, reason_t *reason) {
    return is_valid_internal(start, end, reason);
}

bool is_valid(const char *str, reason_t *reason) {
    size_t len = strlen(str);
    const char *end = str + len;
    return is_valid_internal(str, end, reason);
}

} // namespace utf8
<|endoftext|>


<commit_before>/***************************************************************************
 *  mng/mng.h
 *
 *  Part of the STXXL. See http://stxxl.sourceforge.net
 *
 *  Copyright (C) 2002-2004 Roman Dementiev <dementiev@mpi-sb.mpg.de>
 *  Copyright (C) 2008 Andreas Beckmann <beckmann@cs.uni-frankfurt.de>
 *
 *  Distributed under the Boost Software License, Version 1.0.
 *  (See accompanying file LICENSE_1_0.txt or copy at
 *  http://www.boost.org/LICENSE_1_0.txt)
 **************************************************************************/

#include <stxxl/mng>
#include <stxxl/bits/io/io.h>
#include <stxxl/bits/version.h>

__STXXL_BEGIN_NAMESPACE

void DiskAllocator::dump()
{
    int64 total = 0;
    sortseq::const_iterator cur = free_space.begin();
    STXXL_ERRMSG("Free regions dump:");
    for ( ; cur != free_space.end(); ++cur)
    {
        STXXL_ERRMSG("Free chunk: begin: " << (cur->first) << " size: " << (cur->second));
        total += cur->second;
    }
    STXXL_ERRMSG("Total bytes: " << total);
}

void config::init(const char * config_path)
{
    logger::get_instance();
    STXXL_MSG(get_version_string());
    std::vector<DiskEntry> flash_props;
    std::ifstream cfg_file(config_path);
    if (!cfg_file)
    {
        STXXL_ERRMSG("Warning: no config file found.");
        STXXL_ERRMSG("Using default disk configuration.");
#ifndef BOOST_MSVC
        DiskEntry entry1 = { "/var/tmp/stxxl", "syscall", 1000 * 1024 * 1024, true };
#else
        DiskEntry entry1 = { "", "wincall", 1000 * 1024 * 1024, true };
        char * tmpstr = new char[255];
        stxxl_check_ne_0(GetTempPath(255, tmpstr), resource_error);
        entry1.path = tmpstr;
        entry1.path += "stxxl";
        delete[] tmpstr;
#endif
#if 0
        DiskEntry entry2 =
        { "/tmp/stxxl1", "mmap", 100 * 1024 * 1024, true };
        DiskEntry entry3 =
        { "/tmp/stxxl2", "simdisk", 1000 * 1024 * 1024, false };
#endif
        disks_props.push_back(entry1);
        //disks_props.push_back(entry2);
        //disks_props.push_back(entry3);
    }
    else
    {
        std::string line;

        while (cfg_file >> line)
        {
            std::vector<std::string> tmp = split(line, "=");
            bool is_disk;

            if (tmp[0][0] == '#')
            { }
            else if ((is_disk = (tmp[0] == "disk")) || tmp[0] == "flash")
            {
                tmp = split(tmp[1], ",");
                DiskEntry entry = {
                    tmp[0], tmp[2],
                    int64(atoi(tmp[1].c_str())) * int64(1024 * 1024),
                    false
                };
                if (is_disk)
                    disks_props.push_back(entry);
                else
                    flash_props.push_back(entry);
            }
            else
            {
                std::cerr << "Unknown token " <<
                tmp[0] << std::endl;
            }
        }
        cfg_file.close();
    }

    // put flash devices after regular disks
    first_flash = disks_props.size();
    disks_props.insert(disks_props.end(), flash_props.begin(), flash_props.end());

    if (disks_props.empty())
    {
        STXXL_THROW(std::runtime_error, "config::config", "No disks found in '" << config_path << "' .");
    }
    else
    {
#ifdef STXXL_VERBOSE_DISKS
        for (std::vector<DiskEntry>::const_iterator it =
                 disks_props.begin(); it != disks_props.end();
             it++)
        {
            STXXL_MSG("Disk '" << (*it).path << "' is allocated, space: " <<
                      ((*it).size) / (1024 * 1024) <<
                      " MB, I/O implementation: " << (*it).io_impl);
        }
#else
        int64 total_size = 0;
        for (std::vector<DiskEntry>::const_iterator it =
                 disks_props.begin(); it != disks_props.end();
             it++)
            total_size += (*it).size;

        STXXL_MSG("" << disks_props.size() << " disks are allocated, total space: " <<
                  (total_size / (1024 * 1024)) <<
                  " MB");
#endif
    }
}

file * FileCreator::create(const std::string & io_impl,
                                  const std::string & filename,
                                  int options, int disk)
{
    if (io_impl == "syscall")
    {
        ufs_file_base * result = new syscall_file(filename, options, disk);
        result->lock();
        return result;
    }
#ifndef BOOST_MSVC
    else if (io_impl == "mmap")
    {
        ufs_file_base * result = new mmap_file(filename, options, disk);
        result->lock();
        return result;
    }
    else if (io_impl == "simdisk")
    {
        ufs_file_base * result = new sim_disk_file(filename, options, disk);
        result->lock();
        return result;
    }
#else
    else if (io_impl == "wincall")
    {
        wfs_file_base * result = new wincall_file(filename, options, disk);
        result->lock();
        return result;
    }
#endif
#ifdef STXXL_BOOST_CONFIG
    else if (io_impl == "boostfd")
    {
        return new boostfd_file(filename, options, disk);
    }
#endif
    else if (io_impl == "memory")
    {
        mem_file * result = new mem_file(disk);
        result->lock();
        return result;
    }
    else if (io_impl == "fileperblock")
    {
        fileperblock_file<syscall_file> * result = new fileperblock_file<syscall_file>(filename, options, 8 * 1048576, disk);
        result->lock();
        return result;
    }

    STXXL_THROW(std::runtime_error, "FileCreator::create", "Unsupported disk I/O implementation " <<
                io_impl << " .");

    return NULL;
}

block_manager::block_manager()
{
    FileCreator fc;
    debugmon::get_instance();
    config * cfg = config::get_instance();

    ndisks = cfg->disks_number();
    disk_allocators = new DiskAllocator *[ndisks];
    disk_files = new file *[ndisks];

    for (unsigned i = 0; i < ndisks; i++)
    {
        disk_files[i] = fc.create(cfg->disk_io_impl(i),
                                  cfg->disk_path(i),
                                  file::CREAT | file::RDWR | file::DIRECT, i);
        disk_files[i]->set_size(cfg->disk_size(i));
        disk_allocators[i] = new DiskAllocator(cfg->disk_size(i));
    }
}

block_manager::~block_manager()
{
    STXXL_VERBOSE1("Block manager destructor");
    for (unsigned i = 0; i < ndisks; i++)
    {
        delete disk_allocators[i];
        delete disk_files[i];
    }
    delete[] disk_allocators;
    delete[] disk_files;
}

__STXXL_END_NAMESPACE
// vim: et:ts=4:sw=4
<commit_msg>Configurable block size for fileperblock.<commit_after>/***************************************************************************
 *  mng/mng.h
 *
 *  Part of the STXXL. See http://stxxl.sourceforge.net
 *
 *  Copyright (C) 2002-2004 Roman Dementiev <dementiev@mpi-sb.mpg.de>
 *  Copyright (C) 2008 Andreas Beckmann <beckmann@cs.uni-frankfurt.de>
 *
 *  Distributed under the Boost Software License, Version 1.0.
 *  (See accompanying file LICENSE_1_0.txt or copy at
 *  http://www.boost.org/LICENSE_1_0.txt)
 **************************************************************************/

#include <sstream>
#include <stxxl/mng>
#include <stxxl/bits/io/io.h>
#include <stxxl/bits/version.h>

__STXXL_BEGIN_NAMESPACE

void DiskAllocator::dump()
{
    int64 total = 0;
    sortseq::const_iterator cur = free_space.begin();
    STXXL_ERRMSG("Free regions dump:");
    for ( ; cur != free_space.end(); ++cur)
    {
        STXXL_ERRMSG("Free chunk: begin: " << (cur->first) << " size: " << (cur->second));
        total += cur->second;
    }
    STXXL_ERRMSG("Total bytes: " << total);
}

void config::init(const char * config_path)
{
    logger::get_instance();
    STXXL_MSG(get_version_string());
    std::vector<DiskEntry> flash_props;
    std::ifstream cfg_file(config_path);
    if (!cfg_file)
    {
        STXXL_ERRMSG("Warning: no config file found.");
        STXXL_ERRMSG("Using default disk configuration.");
#ifndef BOOST_MSVC
        DiskEntry entry1 = { "/var/tmp/stxxl", "syscall", 1000 * 1024 * 1024, true };
#else
        DiskEntry entry1 = { "", "wincall", 1000 * 1024 * 1024, true };
        char * tmpstr = new char[255];
        stxxl_check_ne_0(GetTempPath(255, tmpstr), resource_error);
        entry1.path = tmpstr;
        entry1.path += "stxxl";
        delete[] tmpstr;
#endif
#if 0
        DiskEntry entry2 =
        { "/tmp/stxxl1", "mmap", 100 * 1024 * 1024, true };
        DiskEntry entry3 =
        { "/tmp/stxxl2", "simdisk", 1000 * 1024 * 1024, false };
#endif
        disks_props.push_back(entry1);
        //disks_props.push_back(entry2);
        //disks_props.push_back(entry3);
    }
    else
    {
        std::string line;

        while (cfg_file >> line)
        {
            std::vector<std::string> tmp = split(line, "=");
            bool is_disk;

            if (tmp[0][0] == '#')
            { }
            else if ((is_disk = (tmp[0] == "disk")) || tmp[0] == "flash")
            {
                tmp = split(tmp[1], ",");
                DiskEntry entry = {
                    tmp[0], tmp[2],
                    int64(atoi(tmp[1].c_str())) * int64(1024 * 1024),
                    false
                };
                if (is_disk)
                    disks_props.push_back(entry);
                else
                    flash_props.push_back(entry);
            }
            else
            {
                std::cerr << "Unknown token " <<
                tmp[0] << std::endl;
            }
        }
        cfg_file.close();
    }

    // put flash devices after regular disks
    first_flash = disks_props.size();
    disks_props.insert(disks_props.end(), flash_props.begin(), flash_props.end());

    if (disks_props.empty())
    {
        STXXL_THROW(std::runtime_error, "config::config", "No disks found in '" << config_path << "' .");
    }
    else
    {
#ifdef STXXL_VERBOSE_DISKS
        for (std::vector<DiskEntry>::const_iterator it =
                 disks_props.begin(); it != disks_props.end();
             it++)
        {
            STXXL_MSG("Disk '" << (*it).path << "' is allocated, space: " <<
                      ((*it).size) / (1024 * 1024) <<
                      " MB, I/O implementation: " << (*it).io_impl);
        }
#else
        int64 total_size = 0;
        for (std::vector<DiskEntry>::const_iterator it =
                 disks_props.begin(); it != disks_props.end();
             it++)
            total_size += (*it).size;

        STXXL_MSG("" << disks_props.size() << " disks are allocated, total space: " <<
                  (total_size / (1024 * 1024)) <<
                  " MB");
#endif
    }
}

file * FileCreator::create(const std::string & io_impl,
                                  const std::string & filename,
                                  int options, int disk)
{
    if (io_impl == "syscall")
    {
        ufs_file_base * result = new syscall_file(filename, options, disk);
        result->lock();
        return result;
    }
#ifndef BOOST_MSVC
    else if (io_impl == "mmap")
    {
        ufs_file_base * result = new mmap_file(filename, options, disk);
        result->lock();
        return result;
    }
    else if (io_impl == "simdisk")
    {
        ufs_file_base * result = new sim_disk_file(filename, options, disk);
        result->lock();
        return result;
    }
#else
    else if (io_impl == "wincall")
    {
        wfs_file_base * result = new wincall_file(filename, options, disk);
        result->lock();
        return result;
    }
#endif
#ifdef STXXL_BOOST_CONFIG
    else if (io_impl == "boostfd")
    {
        return new boostfd_file(filename, options, disk);
    }
#endif
    else if (io_impl == "memory")
    {
        mem_file * result = new mem_file(disk);
        result->lock();
        return result;
    }
    else if (io_impl.find_first_of("fileperblock(") == 0)
    {
        std::istringstream input(io_impl);
        input.ignore(std::string("fileperblock(").size());
        size_t block_size;
        input >> block_size;
        if(block_size <= 0)
            STXXL_THROW(std::runtime_error, "FileCreator::create", "No/incorrect block size given for fileperblock.");

        fileperblock_file<syscall_file> * result = new fileperblock_file<syscall_file>(filename, options, block_size, disk);
        result->lock();
        return result;
    }

    STXXL_THROW(std::runtime_error, "FileCreator::create", "Unsupported disk I/O implementation " <<
                io_impl << " .");

    return NULL;
}

block_manager::block_manager()
{
    FileCreator fc;
    debugmon::get_instance();
    config * cfg = config::get_instance();

    ndisks = cfg->disks_number();
    disk_allocators = new DiskAllocator *[ndisks];
    disk_files = new file *[ndisks];

    for (unsigned i = 0; i < ndisks; i++)
    {
        disk_files[i] = fc.create(cfg->disk_io_impl(i),
                                  cfg->disk_path(i),
                                  file::CREAT | file::RDWR | file::DIRECT, i);
        disk_files[i]->set_size(cfg->disk_size(i));
        disk_allocators[i] = new DiskAllocator(cfg->disk_size(i));
    }
}

block_manager::~block_manager()
{
    STXXL_VERBOSE1("Block manager destructor");
    for (unsigned i = 0; i < ndisks; i++)
    {
        delete disk_allocators[i];
        delete disk_files[i];
    }
    delete[] disk_allocators;
    delete[] disk_files;
}

__STXXL_END_NAMESPACE
// vim: et:ts=4:sw=4
<|endoftext|>