<commit_before>/**************************************************************************
**
** Copyright (C) 2013 Openismus GmbH.
** Authors: Peter Penz (ppenz@openismus.com)
**          Patricia Santana Cruz (patriciasantanacruz@gmail.com)
** Contact: http://www.qt-project.org/legal
**
** 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 "makefileparser.h"

#include <utils/qtcassert.h>

#include <QFile>
#include <QDir>
#include <QFileInfoList>
#include <QMutexLocker>

using namespace AutotoolsProjectManager::Internal;

MakefileParser::MakefileParser(const QString &makefile) :
    QObject(),
    m_success(false),
    m_cancel(false),
    m_mutex(),
    m_makefile(makefile),
    m_executable(),
    m_sources(),
    m_makefiles(),
    m_includePaths(),
    m_line(),
    m_textStream()
{
}

MakefileParser::~MakefileParser()
{
    delete m_textStream.device();
}

bool MakefileParser::parse()
{
    m_mutex.lock();
    m_cancel = false;
    m_mutex.unlock(),

    m_success = true;
    m_executable.clear();
    m_sources.clear();
    m_makefiles.clear();

    QFile *file = new QFile(m_makefile);
    if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
        qWarning("%s: %s", qPrintable(m_makefile), qPrintable(file->errorString()));
        delete file;
        return false;
    }

    QFileInfo info(m_makefile);
    m_makefiles.append(info.fileName());

    emit status(tr("Parsing %1 in directory %2").arg(info.fileName()).arg(info.absolutePath()));

    m_textStream.setDevice(file);

    do {
        m_line = m_textStream.readLine();
        switch (topTarget()) {
        case AmDefaultSourceExt: parseDefaultSourceExtensions(); break;
        case BinPrograms: parseBinPrograms(); break;
        case BuiltSources: break; // TODO: Add to m_sources?
        case Sources: parseSources(); break;
        case SubDirs: parseSubDirs(); break;
        case Undefined:
        default: break;
        }
    } while (!m_line.isNull());

    parseIncludePaths();

    return m_success;
}

QStringList MakefileParser::sources() const
{
    return m_sources;
}

QStringList MakefileParser::makefiles() const
{
    return m_makefiles;
}

QString MakefileParser::executable() const
{
    return m_executable;
}

QStringList MakefileParser::includePaths() const
{
    return m_includePaths;
}

void MakefileParser::cancel()
{
    QMutexLocker locker(&m_mutex);
    m_cancel = true;
}

bool MakefileParser::isCanceled() const
{
    QMutexLocker locker(&m_mutex);
    return m_cancel;
}

MakefileParser::TopTarget MakefileParser::topTarget() const
{
    const QString line = m_line.simplified();

    if (line.isEmpty() || line.startsWith(QLatin1Char('#')))
        return Undefined;

    const QString id = parseIdentifierBeforeAssign(line);
    if (id.isEmpty())
        return Undefined;

    if (id == QLatin1String("AM_DEFAULT_SOURCE_EXT"))
        return AmDefaultSourceExt;
    if (id == QLatin1String("bin_PROGRAMS"))
        return BinPrograms;
    if (id == QLatin1String("BUILT_SOURCES"))
        return BuiltSources;
    if (id == QLatin1String("SUBDIRS") || id == QLatin1String("DIST_SUBDIRS"))
        return SubDirs;
    if (id.endsWith(QLatin1String("_SOURCES")))
        return Sources;

    return Undefined;
}

void MakefileParser::parseBinPrograms()
{
    QTC_ASSERT(m_line.contains(QLatin1String("bin_PROGRAMS")), return);
    const QStringList binPrograms = targetValues();

    // TODO: are multiple values possible?
    if (binPrograms.size() == 1) {
        QFileInfo info(binPrograms.first());
        m_executable = info.fileName();
    }
}

void MakefileParser::parseSources()
{
    QTC_ASSERT(m_line.contains(QLatin1String("_SOURCES")), return);

    bool hasVariables = false;
    m_sources.append(targetValues(&hasVariables));

    // Skip parsing of Makefile.am for getting the sub directories,
    // as variables have been used. As fallback all sources will be added.
    if (hasVariables)
        addAllSources();

    // Duplicates might be possible in combination with 'AM_DEFAULT_SOURCE_EXT ='
    m_sources.removeDuplicates();

    // TODO: Definitions like "SOURCES = ../src.cpp" are ignored currently.
    // This case must be handled correctly in MakefileParser::parseSubDirs(),
    // where the current sub directory must be shortened.
    QStringList::iterator it = m_sources.begin();
    while (it != m_sources.end()) {
        if ((*it).startsWith(QLatin1String("..")))
            it = m_sources.erase(it);
        else
            ++it;
    }
}

void MakefileParser::parseDefaultSourceExtensions()
{
    QTC_ASSERT(m_line.contains(QLatin1String("AM_DEFAULT_SOURCE_EXT")), return);
    const QStringList extensions = targetValues();
    if (extensions.isEmpty()) {
        m_success = false;
        return;
    }

    QFileInfo info(m_makefile);
    const QString dirName = info.absolutePath();
    m_sources.append(directorySources(dirName, extensions));

    // Duplicates might be possible in combination with '_SOURCES ='
    m_sources.removeDuplicates();
}

void MakefileParser::parseSubDirs()
{
    QTC_ASSERT(m_line.contains(QLatin1String("SUBDIRS")), return);
    if (isCanceled()) {
        m_success = false;
        return;
    }

    QFileInfo info(m_makefile);
    const QString path = info.absolutePath();
    const QString makefileName = info.fileName();

    bool hasVariables = false;
    QStringList subDirs = targetValues(&hasVariables);
    if (hasVariables) {
        // Skip parsing of Makefile.am for getting the sub directories,
        // as variables have been used. As fallback all sources will be added.
        addAllSources();
        return;
    }

    // If the SUBDIRS values contain a '.' or a variable like $(test),
    // all the sub directories of the current folder must get parsed.
    bool hasDotSubDir = false;
    QStringList::iterator it = subDirs.begin();
    while (it != subDirs.end()) {
        // Erase all entries that represent a '.'
        if ((*it) == QLatin1String(".")) {
            hasDotSubDir = true;
            it = subDirs.erase(it);
        } else {
            ++it;
        }
    }
    if (hasDotSubDir) {
        // Add all sub directories of the current folder
        QDir dir(path);
        dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
        foreach (const QFileInfo& info, dir.entryInfoList()) {
            subDirs.append(info.fileName());
        }
    }
    subDirs.removeDuplicates();

    // Delegate the parsing of all sub directories to a local
    // makefile parser and merge the results
    foreach (const QString& subDir, subDirs) {
        const QChar slash = QLatin1Char('/');
        const QString subDirMakefile = path + slash + subDir
                                       + slash + makefileName;

        // Parse sub directory
        QFile file(subDirMakefile);

        // Don't try to parse a file, that might not exist (e. g.
        // if SUBDIRS specifies a 'po' directory).
        if (!file.exists())
            continue;

        MakefileParser parser(subDirMakefile);
        connect(&parser, SIGNAL(status(QString)), this, SIGNAL(status(QString)));
        const bool success = parser.parse();

        // Don't return, try to parse as many sub directories
        // as possible
        if (!success)
            m_success = false;

        m_makefiles.append(subDir + slash + makefileName);

        // Append the sources of the sub directory to the
        // current sources
        foreach (const QString& source, parser.sources())
            m_sources.append(subDir + slash + source);

        // Duplicates might be possible in combination with several
        // "..._SUBDIRS" targets
        m_makefiles.removeDuplicates();
        m_sources.removeDuplicates();
    }

    if (subDirs.isEmpty())
        m_success = false;
}

QStringList MakefileParser::directorySources(const QString &directory,
                                             const QStringList &extensions)
{
    if (isCanceled()) {
        m_success = false;
        return QStringList();
    }

    emit status(tr("Parsing directory %1").arg(directory));

    QStringList list; // return value

    QDir dir(directory);
    dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);

    const QFileInfoList infos = dir.entryInfoList();
    foreach (const QFileInfo& info, infos) {
        if (info.isDir()) {
            // Append recursively sources from the sub directory
            const QStringList subDirSources = directorySources(info.absoluteFilePath(),
                                                               extensions);
            const QString dirPath = info.fileName();
            foreach (const QString& subDirSource, subDirSources)
                list.append(dirPath + QLatin1Char('/') + subDirSource);
        } else {
            // Check whether the file matches to an extension
            foreach (const QString& extension, extensions) {
                if (info.fileName().endsWith(extension)) {
                    list.append(info.fileName());
                    appendHeader(list, dir, info.baseName());
                    break;
                }
            }
        }
    }

    return list;
}

QStringList MakefileParser::targetValues(bool *hasVariables)
{
    QStringList values;
    if (hasVariables != 0)
        *hasVariables = false;

    const int index = m_line.indexOf(QLatin1Char('='));
    if (index < 0) {
        m_success = false;
        return QStringList();
    }

    m_line.remove(0, index + 1); // remove the 'target = ' prefix

    bool endReached = false;
    do {
        m_line = m_line.simplified();

        // Get all values of a line separated by spaces.
        // Values representing a variable like $(value) get
        // removed currently.
        QStringList lineValues = m_line.split(QLatin1Char(' '), QString::SkipEmptyParts);
        QStringList::iterator it = lineValues.begin();
        while (it != lineValues.end()) {
            if ((*it).startsWith(QLatin1String("$("))) {
                it = lineValues.erase(it);
                if (hasVariables != 0)
                    *hasVariables = true;
            } else {
                ++it;
            }
        }

        endReached = lineValues.isEmpty();
        if (!endReached) {
            const QChar backSlash = QLatin1Char('\\');
            QString last = lineValues.last();
            if (last.endsWith(backSlash)) {
                // The last value contains a backslash. Remove the
                // backslash and replace the last value.
                lineValues.pop_back();
                last.remove(backSlash);
                if (!last.isEmpty())
                    lineValues.push_back(last);

                values.append(lineValues);
                m_line = m_textStream.readLine();
                endReached = m_line.isNull();
            } else {
                values.append(lineValues);
                endReached = true;
            }
        }
    } while (!endReached);

    return values;
}

void MakefileParser::appendHeader(QStringList &list,  const QDir &dir, const QString &fileName)
{
    const char *const headerExtensions[] = { ".h", ".hh", ".hg", ".hxx", ".hpp", 0 };
    int i = 0;
    while (headerExtensions[i] != 0) {
        const QString headerFile = fileName + QLatin1String(headerExtensions[i]);
        QFileInfo fileInfo(dir, headerFile);
        if (fileInfo.exists())
            list.append(headerFile);
        ++i;
    }
}

QString MakefileParser::parseIdentifierBeforeAssign(const QString &line)
{
    int end = 0;
    for (; end < line.size(); ++end)
        if (!line[end].isLetterOrNumber() && line[end] != QLatin1Char('_'))
            break;

    QString ret = line.left(end);
    while (end < line.size() && line[end].isSpace())
        ++end;
    return (line[end] == QLatin1Char('=')) ? ret : QString();
}

void MakefileParser::addAllSources()
{
    QStringList extensions;
    extensions << QLatin1String(".c")
               << QLatin1String(".cpp")
               << QLatin1String(".cc")
               << QLatin1String(".cxx")
               << QLatin1String(".ccg");
    QFileInfo info(m_makefile);
    m_sources.append(directorySources(info.absolutePath(), extensions));
    m_sources.removeDuplicates();
}

void MakefileParser::parseIncludePaths()
{
    QFileInfo info(m_makefile);
    const QString dirName = info.absolutePath();

    QFile file(dirName + QLatin1String("/Makefile"));
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    // TODO: The parsing is done very poor. Comments are ignored and targets
    // are ignored too. Whether it is worth to improve this, depends on whether
    // we want to parse the generated Makefile at all or whether we want to
    // improve the Makefile.am parsing to be aware of variables.
    QTextStream textStream(&file);
    QString line;
    do {
        line = textStream.readLine();
        QStringList terms = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
        foreach (const QString &term, terms) {
            if (term.startsWith(QLatin1String("-I"))) {
                QString includePath = term.right(term.length() - 2); // remove the "-I"
                if (includePath == QLatin1String("."))
                    includePath = dirName;
                if (!includePath.isEmpty())
                    m_includePaths += includePath;
            }
        }
    } while (!line.isNull());

    m_includePaths.removeDuplicates();
}
<commit_msg>Autotools: fixed crash in Debug build<commit_after>/**************************************************************************
**
** Copyright (C) 2013 Openismus GmbH.
** Authors: Peter Penz (ppenz@openismus.com)
**          Patricia Santana Cruz (patriciasantanacruz@gmail.com)
** Contact: http://www.qt-project.org/legal
**
** 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 "makefileparser.h"

#include <utils/qtcassert.h>

#include <QFile>
#include <QDir>
#include <QFileInfoList>
#include <QMutexLocker>

using namespace AutotoolsProjectManager::Internal;

MakefileParser::MakefileParser(const QString &makefile) :
    QObject(),
    m_success(false),
    m_cancel(false),
    m_mutex(),
    m_makefile(makefile),
    m_executable(),
    m_sources(),
    m_makefiles(),
    m_includePaths(),
    m_line(),
    m_textStream()
{
}

MakefileParser::~MakefileParser()
{
    delete m_textStream.device();
}

bool MakefileParser::parse()
{
    m_mutex.lock();
    m_cancel = false;
    m_mutex.unlock(),

    m_success = true;
    m_executable.clear();
    m_sources.clear();
    m_makefiles.clear();

    QFile *file = new QFile(m_makefile);
    if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
        qWarning("%s: %s", qPrintable(m_makefile), qPrintable(file->errorString()));
        delete file;
        return false;
    }

    QFileInfo info(m_makefile);
    m_makefiles.append(info.fileName());

    emit status(tr("Parsing %1 in directory %2").arg(info.fileName()).arg(info.absolutePath()));

    m_textStream.setDevice(file);

    do {
        m_line = m_textStream.readLine();
        switch (topTarget()) {
        case AmDefaultSourceExt: parseDefaultSourceExtensions(); break;
        case BinPrograms: parseBinPrograms(); break;
        case BuiltSources: break; // TODO: Add to m_sources?
        case Sources: parseSources(); break;
        case SubDirs: parseSubDirs(); break;
        case Undefined:
        default: break;
        }
    } while (!m_line.isNull());

    parseIncludePaths();

    return m_success;
}

QStringList MakefileParser::sources() const
{
    return m_sources;
}

QStringList MakefileParser::makefiles() const
{
    return m_makefiles;
}

QString MakefileParser::executable() const
{
    return m_executable;
}

QStringList MakefileParser::includePaths() const
{
    return m_includePaths;
}

void MakefileParser::cancel()
{
    QMutexLocker locker(&m_mutex);
    m_cancel = true;
}

bool MakefileParser::isCanceled() const
{
    QMutexLocker locker(&m_mutex);
    return m_cancel;
}

MakefileParser::TopTarget MakefileParser::topTarget() const
{
    const QString line = m_line.simplified();

    if (line.isEmpty() || line.startsWith(QLatin1Char('#')))
        return Undefined;

    const QString id = parseIdentifierBeforeAssign(line);
    if (id.isEmpty())
        return Undefined;

    if (id == QLatin1String("AM_DEFAULT_SOURCE_EXT"))
        return AmDefaultSourceExt;
    if (id == QLatin1String("bin_PROGRAMS"))
        return BinPrograms;
    if (id == QLatin1String("BUILT_SOURCES"))
        return BuiltSources;
    if (id == QLatin1String("SUBDIRS") || id == QLatin1String("DIST_SUBDIRS"))
        return SubDirs;
    if (id.endsWith(QLatin1String("_SOURCES")))
        return Sources;

    return Undefined;
}

void MakefileParser::parseBinPrograms()
{
    QTC_ASSERT(m_line.contains(QLatin1String("bin_PROGRAMS")), return);
    const QStringList binPrograms = targetValues();

    // TODO: are multiple values possible?
    if (binPrograms.size() == 1) {
        QFileInfo info(binPrograms.first());
        m_executable = info.fileName();
    }
}

void MakefileParser::parseSources()
{
    QTC_ASSERT(m_line.contains(QLatin1String("_SOURCES")), return);

    bool hasVariables = false;
    m_sources.append(targetValues(&hasVariables));

    // Skip parsing of Makefile.am for getting the sub directories,
    // as variables have been used. As fallback all sources will be added.
    if (hasVariables)
        addAllSources();

    // Duplicates might be possible in combination with 'AM_DEFAULT_SOURCE_EXT ='
    m_sources.removeDuplicates();

    // TODO: Definitions like "SOURCES = ../src.cpp" are ignored currently.
    // This case must be handled correctly in MakefileParser::parseSubDirs(),
    // where the current sub directory must be shortened.
    QStringList::iterator it = m_sources.begin();
    while (it != m_sources.end()) {
        if ((*it).startsWith(QLatin1String("..")))
            it = m_sources.erase(it);
        else
            ++it;
    }
}

void MakefileParser::parseDefaultSourceExtensions()
{
    QTC_ASSERT(m_line.contains(QLatin1String("AM_DEFAULT_SOURCE_EXT")), return);
    const QStringList extensions = targetValues();
    if (extensions.isEmpty()) {
        m_success = false;
        return;
    }

    QFileInfo info(m_makefile);
    const QString dirName = info.absolutePath();
    m_sources.append(directorySources(dirName, extensions));

    // Duplicates might be possible in combination with '_SOURCES ='
    m_sources.removeDuplicates();
}

void MakefileParser::parseSubDirs()
{
    QTC_ASSERT(m_line.contains(QLatin1String("SUBDIRS")), return);
    if (isCanceled()) {
        m_success = false;
        return;
    }

    QFileInfo info(m_makefile);
    const QString path = info.absolutePath();
    const QString makefileName = info.fileName();

    bool hasVariables = false;
    QStringList subDirs = targetValues(&hasVariables);
    if (hasVariables) {
        // Skip parsing of Makefile.am for getting the sub directories,
        // as variables have been used. As fallback all sources will be added.
        addAllSources();
        return;
    }

    // If the SUBDIRS values contain a '.' or a variable like $(test),
    // all the sub directories of the current folder must get parsed.
    bool hasDotSubDir = false;
    QStringList::iterator it = subDirs.begin();
    while (it != subDirs.end()) {
        // Erase all entries that represent a '.'
        if ((*it) == QLatin1String(".")) {
            hasDotSubDir = true;
            it = subDirs.erase(it);
        } else {
            ++it;
        }
    }
    if (hasDotSubDir) {
        // Add all sub directories of the current folder
        QDir dir(path);
        dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
        foreach (const QFileInfo& info, dir.entryInfoList()) {
            subDirs.append(info.fileName());
        }
    }
    subDirs.removeDuplicates();

    // Delegate the parsing of all sub directories to a local
    // makefile parser and merge the results
    foreach (const QString& subDir, subDirs) {
        const QChar slash = QLatin1Char('/');
        const QString subDirMakefile = path + slash + subDir
                                       + slash + makefileName;

        // Parse sub directory
        QFile file(subDirMakefile);

        // Don't try to parse a file, that might not exist (e. g.
        // if SUBDIRS specifies a 'po' directory).
        if (!file.exists())
            continue;

        MakefileParser parser(subDirMakefile);
        connect(&parser, SIGNAL(status(QString)), this, SIGNAL(status(QString)));
        const bool success = parser.parse();

        // Don't return, try to parse as many sub directories
        // as possible
        if (!success)
            m_success = false;

        m_makefiles.append(subDir + slash + makefileName);

        // Append the sources of the sub directory to the
        // current sources
        foreach (const QString& source, parser.sources())
            m_sources.append(subDir + slash + source);

        // Duplicates might be possible in combination with several
        // "..._SUBDIRS" targets
        m_makefiles.removeDuplicates();
        m_sources.removeDuplicates();
    }

    if (subDirs.isEmpty())
        m_success = false;
}

QStringList MakefileParser::directorySources(const QString &directory,
                                             const QStringList &extensions)
{
    if (isCanceled()) {
        m_success = false;
        return QStringList();
    }

    emit status(tr("Parsing directory %1").arg(directory));

    QStringList list; // return value

    QDir dir(directory);
    dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);

    const QFileInfoList infos = dir.entryInfoList();
    foreach (const QFileInfo& info, infos) {
        if (info.isDir()) {
            // Append recursively sources from the sub directory
            const QStringList subDirSources = directorySources(info.absoluteFilePath(),
                                                               extensions);
            const QString dirPath = info.fileName();
            foreach (const QString& subDirSource, subDirSources)
                list.append(dirPath + QLatin1Char('/') + subDirSource);
        } else {
            // Check whether the file matches to an extension
            foreach (const QString& extension, extensions) {
                if (info.fileName().endsWith(extension)) {
                    list.append(info.fileName());
                    appendHeader(list, dir, info.baseName());
                    break;
                }
            }
        }
    }

    return list;
}

QStringList MakefileParser::targetValues(bool *hasVariables)
{
    QStringList values;
    if (hasVariables != 0)
        *hasVariables = false;

    const int index = m_line.indexOf(QLatin1Char('='));
    if (index < 0) {
        m_success = false;
        return QStringList();
    }

    m_line.remove(0, index + 1); // remove the 'target = ' prefix

    bool endReached = false;
    do {
        m_line = m_line.simplified();

        // Get all values of a line separated by spaces.
        // Values representing a variable like $(value) get
        // removed currently.
        QStringList lineValues = m_line.split(QLatin1Char(' '), QString::SkipEmptyParts);
        QStringList::iterator it = lineValues.begin();
        while (it != lineValues.end()) {
            if ((*it).startsWith(QLatin1String("$("))) {
                it = lineValues.erase(it);
                if (hasVariables != 0)
                    *hasVariables = true;
            } else {
                ++it;
            }
        }

        endReached = lineValues.isEmpty();
        if (!endReached) {
            const QChar backSlash = QLatin1Char('\\');
            QString last = lineValues.last();
            if (last.endsWith(backSlash)) {
                // The last value contains a backslash. Remove the
                // backslash and replace the last value.
                lineValues.pop_back();
                last.remove(backSlash);
                if (!last.isEmpty())
                    lineValues.push_back(last);

                values.append(lineValues);
                m_line = m_textStream.readLine();
                endReached = m_line.isNull();
            } else {
                values.append(lineValues);
                endReached = true;
            }
        }
    } while (!endReached);

    return values;
}

void MakefileParser::appendHeader(QStringList &list,  const QDir &dir, const QString &fileName)
{
    const char *const headerExtensions[] = { ".h", ".hh", ".hg", ".hxx", ".hpp", 0 };
    int i = 0;
    while (headerExtensions[i] != 0) {
        const QString headerFile = fileName + QLatin1String(headerExtensions[i]);
        QFileInfo fileInfo(dir, headerFile);
        if (fileInfo.exists())
            list.append(headerFile);
        ++i;
    }
}

QString MakefileParser::parseIdentifierBeforeAssign(const QString &line)
{
    int end = 0;
    for (; end < line.size(); ++end)
        if (!line[end].isLetterOrNumber() && line[end] != QLatin1Char('_'))
            break;

    QString ret = line.left(end);
    while (end < line.size() && line[end].isSpace())
        ++end;
    return (end < line.size() && line[end] == QLatin1Char('=')) ? ret : QString();
}

void MakefileParser::addAllSources()
{
    QStringList extensions;
    extensions << QLatin1String(".c")
               << QLatin1String(".cpp")
               << QLatin1String(".cc")
               << QLatin1String(".cxx")
               << QLatin1String(".ccg");
    QFileInfo info(m_makefile);
    m_sources.append(directorySources(info.absolutePath(), extensions));
    m_sources.removeDuplicates();
}

void MakefileParser::parseIncludePaths()
{
    QFileInfo info(m_makefile);
    const QString dirName = info.absolutePath();

    QFile file(dirName + QLatin1String("/Makefile"));
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    // TODO: The parsing is done very poor. Comments are ignored and targets
    // are ignored too. Whether it is worth to improve this, depends on whether
    // we want to parse the generated Makefile at all or whether we want to
    // improve the Makefile.am parsing to be aware of variables.
    QTextStream textStream(&file);
    QString line;
    do {
        line = textStream.readLine();
        QStringList terms = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
        foreach (const QString &term, terms) {
            if (term.startsWith(QLatin1String("-I"))) {
                QString includePath = term.right(term.length() - 2); // remove the "-I"
                if (includePath == QLatin1String("."))
                    includePath = dirName;
                if (!includePath.isEmpty())
                    m_includePaths += includePath;
            }
        }
    } while (!line.isNull());

    m_includePaths.removeDuplicates();
}
<|endoftext|>


<commit_before>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// SampleView plugin
//==============================================================================

#include "sampleviewplugin.h"
#include "sampleviewwidget.h"

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

#include <QMainWindow>

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

#include <QIcon>

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

namespace OpenCOR {
namespace SampleView {

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

PLUGININFO_FUNC SampleViewPluginInfo()
{
    Descriptions descriptions;

    descriptions.insert("en", QString::fromUtf8("a plugin that provides a test view."));
    descriptions.insert("fr", QString::fromUtf8("une extension qui fournit une vue de test."));

    return new PluginInfo(PluginInfo::Sample, true, false,
                          QStringList() << "Core" << "Sample",
                          descriptions);
}

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

SampleViewPlugin::SampleViewPlugin() :
    mFileName(QString())
{
}

//==============================================================================
// File handling interface
//==============================================================================

bool SampleViewPlugin::saveFile(const QString &pOldFileName,
                                const QString &pNewFileName)
{
    Q_UNUSED(pOldFileName);
    Q_UNUSED(pNewFileName);

    // We don't handle this interface...

    return false;
}

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

void SampleViewPlugin::fileOpened(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

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

void SampleViewPlugin::filePermissionsChanged(const QString &pFileName)
{
    // The given file has had its permissions changed, so re-initialise our
    // view widget, if needed

    if (!pFileName.compare(mFileName))
        mViewWidget->initialize(pFileName);
}

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

void SampleViewPlugin::fileModified(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

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

void SampleViewPlugin::fileReloaded(const QString &pFileName)
{
    // The given file has been reloaded, so re-initialise our view widget, if
    // needed

    if (!pFileName.compare(mFileName))
        mViewWidget->initialize(pFileName);
}

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

void SampleViewPlugin::fileRenamed(const QString &pOldFileName,
                                   const QString &pNewFileName)
{
    Q_UNUSED(pOldFileName);

    // The given file has been renamed, so re-initialise our view widget

    if (!pOldFileName.compare(mFileName)) {
        mFileName = pNewFileName;

        mViewWidget->initialize(pNewFileName);
    }
}

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

void SampleViewPlugin::fileClosed(const QString &pFileName)
{
    // The given file has been closed, so update our internals, if needed

    if (!pFileName.compare(mFileName))
        mFileName = QString();
}

//==============================================================================
// I18n interface
//==============================================================================

void SampleViewPlugin::retranslateUi()
{
    // Retranslate our view widget

    mViewWidget->retranslateUi();
}

//==============================================================================
// Plugin interface
//==============================================================================

void SampleViewPlugin::initializePlugin(QMainWindow *pMainWindow)
{
    // Create our sample view widget

    mViewWidget = new SampleViewWidget(pMainWindow);

    // Hide our sample view widget since it may not initially be shown in our
    // central widget

    mViewWidget->setVisible(false);
}

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

void SampleViewPlugin::finalizePlugin()
{
    // We don't handle this interface...
}

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

void SampleViewPlugin::pluginInitialized(const Plugins &pLoadedPlugins)
{
    Q_UNUSED(pLoadedPlugins);

    // We don't handle this interface...
}

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

void SampleViewPlugin::loadSettings(QSettings *pSettings)
{
    Q_UNUSED(pSettings);

    // We don't handle this interface...
}

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

void SampleViewPlugin::saveSettings(QSettings *pSettings) const
{
    Q_UNUSED(pSettings);

    // We don't handle this interface...
}

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

void SampleViewPlugin::handleAction(const QUrl &pUrl)
{
    Q_UNUSED(pUrl);

    // We don't handle this interface...
}

//==============================================================================
// View interface
//==============================================================================

ViewInterface::Mode SampleViewPlugin::viewMode() const
{
    // Return our mode

    return ViewInterface::Sample;
}

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

QStringList SampleViewPlugin::viewMimeTypes() const
{
    // Return the MIME types we support
    // Note: we allow any kind of file, hence our empty string list...

    return QStringList();
}

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

void SampleViewPlugin::initializeView()
{
    // We don't handle this interface...
}

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

void SampleViewPlugin::finalizeView()
{
    // We don't handle this interface...
}

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

QWidget * SampleViewPlugin::viewWidget(const QString &pFileName,
                                       const bool &pCreate)
{
    // Update our sample view widget using the given file

    if (pCreate) {
        mFileName = pFileName;

        mViewWidget->initialize(pFileName);

        return mViewWidget;
    } else {
        mFileName = QString();

        return 0;
    }
}

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

void SampleViewPlugin::removeViewWidget(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

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

QString SampleViewPlugin::viewName() const
{
    // Return our sample view's name

    return tr("Sample");
}

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

QIcon SampleViewPlugin::fileTabIcon(const QString &pFileName) const
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...

    return QIcon();
}

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

}   // namespace SampleView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Some work towards writing some sample plugins (#337) [ci skip].<commit_after>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// SampleView plugin
//==============================================================================

#include "sampleviewplugin.h"
#include "sampleviewwidget.h"

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

#include <QMainWindow>

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

#include <QIcon>

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

namespace OpenCOR {
namespace SampleView {

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

PLUGININFO_FUNC SampleViewPluginInfo()
{
    Descriptions descriptions;

    descriptions.insert("en", QString::fromUtf8("a plugin that provides a test view."));
    descriptions.insert("fr", QString::fromUtf8("une extension qui fournit une vue de test."));

    return new PluginInfo(PluginInfo::Sample, true, false,
                          QStringList() << "Core" << "Sample",
                          descriptions);
}

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

SampleViewPlugin::SampleViewPlugin() :
    mFileName(QString())
{
}

//==============================================================================
// File handling interface
//==============================================================================

bool SampleViewPlugin::saveFile(const QString &pOldFileName,
                                const QString &pNewFileName)
{
    Q_UNUSED(pOldFileName);
    Q_UNUSED(pNewFileName);

    // We don't handle this interface...

    return false;
}

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

void SampleViewPlugin::fileOpened(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

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

void SampleViewPlugin::filePermissionsChanged(const QString &pFileName)
{
    // The given file has had its permissions changed, so re-initialise our
    // view widget, if needed

    if (!pFileName.compare(mFileName))
        mViewWidget->initialize(pFileName);
}

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

void SampleViewPlugin::fileModified(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

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

void SampleViewPlugin::fileReloaded(const QString &pFileName)
{
    // The given file has been reloaded, so re-initialise our view widget, if
    // needed

    if (!pFileName.compare(mFileName))
        mViewWidget->initialize(pFileName);
}

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

void SampleViewPlugin::fileRenamed(const QString &pOldFileName,
                                   const QString &pNewFileName)
{
    Q_UNUSED(pOldFileName);

    // The given file has been renamed, so re-initialise our view widget

    if (!pOldFileName.compare(mFileName)) {
        mFileName = pNewFileName;

        mViewWidget->initialize(pNewFileName);
    }
}

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

void SampleViewPlugin::fileClosed(const QString &pFileName)
{
    // The given file has been closed, so update our internals, if needed

    if (!pFileName.compare(mFileName))
        mFileName = QString();
}

//==============================================================================
// I18n interface
//==============================================================================

void SampleViewPlugin::retranslateUi()
{
    // Retranslate our view widget, if needed

    if (!mFileName.isEmpty())
        mViewWidget->retranslateUi();
}

//==============================================================================
// Plugin interface
//==============================================================================

void SampleViewPlugin::initializePlugin(QMainWindow *pMainWindow)
{
    // Create our sample view widget

    mViewWidget = new SampleViewWidget(pMainWindow);

    // Hide our sample view widget since it may not initially be shown in our
    // central widget

    mViewWidget->setVisible(false);
}

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

void SampleViewPlugin::finalizePlugin()
{
    // We don't handle this interface...
}

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

void SampleViewPlugin::pluginInitialized(const Plugins &pLoadedPlugins)
{
    Q_UNUSED(pLoadedPlugins);

    // We don't handle this interface...
}

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

void SampleViewPlugin::loadSettings(QSettings *pSettings)
{
    Q_UNUSED(pSettings);

    // We don't handle this interface...
}

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

void SampleViewPlugin::saveSettings(QSettings *pSettings) const
{
    Q_UNUSED(pSettings);

    // We don't handle this interface...
}

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

void SampleViewPlugin::handleAction(const QUrl &pUrl)
{
    Q_UNUSED(pUrl);

    // We don't handle this interface...
}

//==============================================================================
// View interface
//==============================================================================

ViewInterface::Mode SampleViewPlugin::viewMode() const
{
    // Return our mode

    return ViewInterface::Sample;
}

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

QStringList SampleViewPlugin::viewMimeTypes() const
{
    // Return the MIME types we support
    // Note: we allow any kind of file, hence our empty string list...

    return QStringList();
}

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

void SampleViewPlugin::initializeView()
{
    // We don't handle this interface...
}

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

void SampleViewPlugin::finalizeView()
{
    // We don't handle this interface...
}

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

QWidget * SampleViewPlugin::viewWidget(const QString &pFileName,
                                       const bool &pCreate)
{
    // Update our sample view widget using the given file

    if (pCreate) {
        mFileName = pFileName;

        mViewWidget->initialize(pFileName);

        return mViewWidget;
    } else {
        mFileName = QString();

        return 0;
    }
}

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

void SampleViewPlugin::removeViewWidget(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

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

QString SampleViewPlugin::viewName() const
{
    // Return our sample view's name

    return tr("Sample");
}

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

QIcon SampleViewPlugin::fileTabIcon(const QString &pFileName) const
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...

    return QIcon();
}

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

}   // namespace SampleView
}   // namespace OpenCOR

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


<commit_before>#pragma once

#include "types.hpp"
#include <mach/mach_time.h>
#include <optional>
#include <pqrs/dispatcher.hpp>
#include <pqrs/osx/iokit_hid_device.hpp>

namespace krbn {
class hid_keyboard_caps_lock_led_state_manager final : public pqrs::dispatcher::extra::dispatcher_client {
public:
  hid_keyboard_caps_lock_led_state_manager(IOHIDDeviceRef device) : dispatcher_client(),
                                                                    device_(device),
                                                                    timer_(*this) {
    if (device_) {
      pqrs::osx::iokit_hid_device hid_device(*device_);
      for (const auto& e : hid_device.make_elements()) {
        auto usage_page = pqrs::osx::iokit_hid_usage_page(IOHIDElementGetUsagePage(*e));
        auto usage = pqrs::osx::iokit_hid_usage(IOHIDElementGetUsage(*e));

        if (usage_page == pqrs::osx::iokit_hid_usage_page_leds &&
            usage == pqrs::osx::iokit_hid_usage_led_caps_lock) {
          element_ = e;
        }
      }
    }
  }

  ~hid_keyboard_caps_lock_led_state_manager(void) {
    detach_from_dispatcher([this] {
      timer_.stop();
    });
  }

  void set_state(std::optional<led_state> value) {
    std::lock_guard<std::mutex> lock(state_mutex_);

    state_ = value;
  }

  void async_start(void) {
    timer_.start(
        [this] {
          update_caps_lock_led();
        },
        std::chrono::milliseconds(1000));
  }

  void async_stop(void) {
    timer_.stop();
  }

private:
  void update_caps_lock_led(void) const {
    if (auto integer_value = make_integer_value()) {
      if (device_ && element_) {
        if (auto value = IOHIDValueCreateWithIntegerValue(kCFAllocatorDefault,
                                                          *element_,
                                                          mach_absolute_time(),
                                                          *integer_value)) {
          IOHIDDeviceSetValue(*device_, *element_, value);

          CFRelease(value);
        }
      }
    }
  }

  std::optional<CFIndex> make_integer_value(void) const {
    std::lock_guard<std::mutex> lock(state_mutex_);

    if (state_ && element_) {
      if (*state_ == led_state::on) {
        return IOHIDElementGetLogicalMax(*element_);
      } else {
        return IOHIDElementGetLogicalMin(*element_);
      }
    }

    return std::nullopt;
  }

  pqrs::cf_ptr<IOHIDDeviceRef> device_;
  pqrs::cf_ptr<IOHIDElementRef> element_;
  std::optional<led_state> state_;
  mutable std::mutex state_mutex_;
  pqrs::dispatcher::extra::timer timer_;
};
} // namespace krbn
<commit_msg>add comment<commit_after>#pragma once

#include "types.hpp"
#include <mach/mach_time.h>
#include <optional>
#include <pqrs/dispatcher.hpp>
#include <pqrs/osx/iokit_hid_device.hpp>

namespace krbn {
class hid_keyboard_caps_lock_led_state_manager final : public pqrs::dispatcher::extra::dispatcher_client {
public:
  hid_keyboard_caps_lock_led_state_manager(IOHIDDeviceRef device) : dispatcher_client(),
                                                                    device_(device),
                                                                    timer_(*this) {
    if (device_) {
      pqrs::osx::iokit_hid_device hid_device(*device_);
      for (const auto& e : hid_device.make_elements()) {
        auto usage_page = pqrs::osx::iokit_hid_usage_page(IOHIDElementGetUsagePage(*e));
        auto usage = pqrs::osx::iokit_hid_usage(IOHIDElementGetUsage(*e));

        if (usage_page == pqrs::osx::iokit_hid_usage_page_leds &&
            usage == pqrs::osx::iokit_hid_usage_led_caps_lock) {
          element_ = e;
        }
      }
    }
  }

  ~hid_keyboard_caps_lock_led_state_manager(void) {
    detach_from_dispatcher([this] {
      timer_.stop();
    });
  }

  void set_state(std::optional<led_state> value) {
    std::lock_guard<std::mutex> lock(state_mutex_);

    state_ = value;
  }

  void async_start(void) {
    timer_.start(
        [this] {
          update_caps_lock_led();
        },
        std::chrono::milliseconds(1000));
  }

  void async_stop(void) {
    timer_.stop();
  }

private:
  void update_caps_lock_led(void) const {
    // macOS 10.12 sometimes synchronize caps lock LED to internal keyboard caps lock state.
    // The behavior causes LED state mismatch because
    // the caps lock state of karabiner_grabber is independent from the hardware caps lock state.
    // Thus, we monitor the LED state and update it if needed.

    if (auto integer_value = make_integer_value()) {
      if (device_ && element_) {
        if (auto value = IOHIDValueCreateWithIntegerValue(kCFAllocatorDefault,
                                                          *element_,
                                                          mach_absolute_time(),
                                                          *integer_value)) {
          IOHIDDeviceSetValue(*device_, *element_, value);

          CFRelease(value);
        }
      }
    }
  }

  std::optional<CFIndex> make_integer_value(void) const {
    std::lock_guard<std::mutex> lock(state_mutex_);

    if (state_ && element_) {
      if (*state_ == led_state::on) {
        return IOHIDElementGetLogicalMax(*element_);
      } else {
        return IOHIDElementGetLogicalMin(*element_);
      }
    }

    return std::nullopt;
  }

  pqrs::cf_ptr<IOHIDDeviceRef> device_;
  pqrs::cf_ptr<IOHIDElementRef> element_;
  std::optional<led_state> state_;
  mutable std::mutex state_mutex_;
  pqrs::dispatcher::extra::timer timer_;
};
} // namespace krbn
<|endoftext|>


<commit_before>// @(#)root/proof:$Name:  $:$Id: TProof.h,v 1.71 2005/10/27 23:28:33 rdm Exp $
// Author: Paul Nilsson   7/12/2005

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TProofResourcesStatic                                                //
//                                                                      //
// Implementation of PROOF static resources.                            //
// The purpose of this class is to provide a standard interface to      //
// static config files. It interprets Proof config files (proof.conf)   //
// and sorts the contents into TProofNodeInfo objects. Master info will //
// be placed in fMaster (of type TProofNodeInfo). Submaster info will   //
// be put in fSubmasterList (a TList of TProofNodeInfo objects), while  //
// workers (and condorworkers) will be placed in fWorkerList (a TList   //
// of TProofNodeInfo objects).                                          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "Riostream.h"
#include "TProofResourcesStatic.h"
#include "TSystem.h"
#include "TProofServ.h"
#include "TProof.h"
#include "TInetAddress.h"
#include "TProofNodeInfo.h"
#include "TProofDebug.h"
#include "TUrl.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TError.h"

ClassImp(TProofResourcesStatic)

//______________________________________________________________________________
TProofResourcesStatic::TProofResourcesStatic()
{
   // This ctor is used in TProofServ::Setup() in combination with GetWorkDir()
   // for a quick scan of the config file to retrieve the work directory.

   // Create master node info and submaster/worker lists, and set default values
   InitResources();
}

//______________________________________________________________________________
TProofResourcesStatic::TProofResourcesStatic(const TString &confDir,
                                             const TString &fileName)
{
   // Using this ctor will retrieve all information in the config file
   // and store it in fMaster, fSubmasterList and fWorkerList,
   // condorworkers will be stored in the fWorkerList.

   // Create master node info and submaster/worker lists, and set default values
   InitResources();

   // Open and read the PROOF config file
   if (!ReadConfigFile(confDir, fileName)) {
      Error("TProofResourcesStatic", "error encountered while reading config file");
      fValid = kFALSE;
   }
}

//______________________________________________________________________________
TProofResourcesStatic::~TProofResourcesStatic()
{
   // Destructor.

   delete fSubmasterList;
   delete fWorkerList;
   delete fMaster;
}

//______________________________________________________________________________
void TProofResourcesStatic::InitResources()
{
   // Create master node info and submaster/worker lists,
   // and set default values.

   // Create master
   fMaster = new TProofNodeInfo();
   fMaster->fNodeType = TProofNodeInfo::GetNodeType("master");
   fFoundMaster = kFALSE; // Set to kTRUE if the config file contains master info

   // Create workers
   fWorkerList = new TList();
   fWorkerList->SetOwner();

   // Create submaster
   fSubmasterList = new TList();
   fSubmasterList->SetOwner();

   // Assume that the config file will be ok
   fValid = kTRUE;
}

//______________________________________________________________________________
TProofNodeInfo *TProofResourcesStatic::GetMaster()
{
   // Get the master node. Only return the master info if it was set
   // in the config file.

   if (fFoundMaster)
      return fMaster;

   return 0;
}

//______________________________________________________________________________
TList *TProofResourcesStatic::GetSubmasters()
{
   // Get the list of submaster nodes.

   return fSubmasterList;
}

//______________________________________________________________________________
TList *TProofResourcesStatic::GetWorkers(void)
{
   // Get the list of worker nodes.

   return fWorkerList;
}

//______________________________________________________________________________
Bool_t TProofResourcesStatic::ReadConfigFile(const TString &confDir,
                                             const TString &fileName)
{
   // Read the PROOF config file and fill the master and worker list.

   Bool_t status = kTRUE;

   PDB(kGlobal,1)
      Info("ReadConfigFile", "using PROOF config file: %s", fileName.Data());

   // Add a proper path to the file name
   fFileName.Form("%s/.%s", gSystem->Getenv("HOME"), fileName.Data());
   PDB(kGlobal,2)
      Info("ReadConfigFile", "checking PROOF config file %s", fFileName.Data());
   if (gSystem->AccessPathName(fFileName, kReadPermission)) {
      fFileName.Form("%s/proof/etc/%s", confDir.Data(), fileName.Data());
      PDB(kGlobal,2)
         Info("ReadConfigFile", "checking PROOF config file %s", fFileName.Data());
      if (gSystem->AccessPathName(fFileName, kReadPermission)) {
         Error("ReadConfigFile", "no PROOF config file found");
         return kFALSE;
      }
   }

   // Open the config file
   fstream infile(fFileName.Data(), std::ios::in);
   if (infile.is_open()) {
      Bool_t isMaster = kFALSE;
      Bool_t isSubmaster = kFALSE;
      Bool_t isWorker = kFALSE;

      // Each line in the file consists of several 'keywords', e.g.
      //   line = "master mypc image=local"
      //     keyword[0] = "master"
      //     keyword[1] = "mypc"
      //     keyword[2] = "image=local"
      // The last keyword has an option "image" with value "local"
      TString line = "";
      TString keyword = "";

      // Read the entire file into the allLines object
      TString allLines = "";
      allLines.ReadString(infile);
      TObjArray *lines = allLines.Tokenize("\n");
      Int_t numberOfLines = lines->GetEntries();

      // Process one line at the time
      for (Int_t j = 0; j < numberOfLines; j++) {
         TObjString *objLine = (TObjString *)lines->At(j);
         line = objLine->GetString();
         line = line.Strip(TString::kBoth);

         // Unless this line was empty or a comment, interpret the line
         if ( !((line(0,1) == "#") || (line == "")) ) {
            TProofNodeInfo *nodeinfo = 0;

            // Reset boolean (condorworkers are treated as a workers)
            isMaster = kFALSE;
            isSubmaster = kFALSE;
            isWorker = kFALSE;

            // Extract all words in the current line
            TObjArray *tokens = line.Tokenize(" ");
            Int_t n = tokens->GetEntries();
            TString option;
            TString value;
            for (Int_t i = 0; i < n; i++) {

               // Extrace one word from the current line
               keyword = ((TObjString *)tokens->At(i))->GetString();

               // Interpret this keyword
               switch (GetInfoType(keyword)) {
               case kNodeType: {
                  if (keyword == "master" || keyword == "node") {
                     nodeinfo = fMaster;
                     nodeinfo->fWorkDir = kPROOF_WorkDir;
                     isMaster = kTRUE;     // will be reset
                     fFoundMaster = kTRUE; // will not be reset
                  }
                  // [either submaster, worker or condorworker]
                  else if (keyword == "submaster") {
                     // Get a submaster info node
                     nodeinfo = CreateNodeInfo(keyword);
                     isSubmaster = kTRUE;
                  } else {
                     // Get a worker or condorworker info node
                     nodeinfo = CreateNodeInfo(keyword);
                     isWorker = kTRUE;
                  }
                  break;
               }
               case kHost: {
                  // Store the host name
                  if (nodeinfo) {
                     nodeinfo->fNodeName = keyword;

                     // Set default image
                     if (isMaster) {
                        TString node = TUrl(nodeinfo->fNodeName).GetHost();
                        nodeinfo->fImage = strstr(nodeinfo->fNodeName, node.Data());
                     } else {
                        // If the node name contains an '@' sign, it should be removed
                        // before copying it into the [default] image info
                        // On what position is the '@' sign? (if there is one)
                        TString tmp = nodeinfo->fNodeName;
                        const Ssiz_t equalPosition = tmp.Index("@", 1, 0, TString::kExact);

                        // Extract the host
                        nodeinfo->fImage = tmp(equalPosition + 1, tmp.Length());
                     }
                  } else {
                     Error("ReadConfigFile","Command not recognized: %s (ignored)",
                           keyword.Data());
                  }
                  break;
               }
               case kOption: {
                  // On what position is the '=' sign?
                  const Ssiz_t equalPosition =
                     keyword.Index("=", 1, 0, TString::kExact);

                  // Extract the option and its value
                  TString tmp = keyword;
                  option = tmp(0, equalPosition);
                  value = tmp(equalPosition + 1, tmp.Length());

                  // Set the node info options
                  SetOption(nodeinfo, option, value);
                  break;
               }
               default:
                  break;
               } // end switch

            } // end if

            // Store the submaster, worker or condorworker
            if (isWorker) {
               fWorkerList->Add(nodeinfo);
            }
            else if (isSubmaster) {
               fSubmasterList->Add(nodeinfo);
            }
         } // else

      } // while (! infile.eof() )
      infile.close();

      // Did the config file contain appropriate master information?
      if (!fFoundMaster) {
         Error("ReadConfigFile","No master info found in config file");
         status = kFALSE;
      } else {
         // Check if the master can run on this node
         TString node = TUrl(fMaster->fNodeName).GetHost();
         TString host = gSystem->GetHostByName(gSystem->HostName()).GetHostName();
         TInetAddress inetaddr = gSystem->GetHostByName(node);
         if ( !(!host.CompareTo(inetaddr.GetHostName()) || (node == "localhost")) ) {
            Error("ReadConfigFile","No appropriate master found in config file");
            status = kFALSE;
         }

         // Check the master work directory
         if (strcmp(gSystem->ExpandPathName(fMaster->GetWorkDir()),
                    gProofServ->GetWorkDir())) {
            Error("ReadConfigFile","Bad work directory: %s", fMaster->GetWorkDir().Data());
            status = kFALSE;
         }
      }
   } // end if (infile.is_open())
   else {
      // Error: could not open file
      status = kFALSE;
   }

   return status;
}

//______________________________________________________________________________
TString TProofResourcesStatic::GetWorkDir(const TString &confDir,
                                          const TString &fileName)
{
   // Read the working directory from the PROOF config file.
   // This method is used by TProofServ::Setup() rather than the full
   // interpretation of the config file as is done in ReadConfigFile().
   // If the workdir option is not specified in the config file,
   // GetWorkDir() will return an empty string.

   TString workDir;
   Bool_t status = kTRUE;

   PDB(kGlobal,1)
      Info("GetWorkDir", "using PROOF config file: %s", fileName.Data());

   // Add a proper path to the file name
   fFileName.Form("%s/.%s", gSystem->Getenv("HOME"), fileName.Data());
   PDB(kGlobal,2)
      Info("GetWorkDir", "checking PROOF config file %s", fFileName.Data());
   if (gSystem->AccessPathName(fFileName, kReadPermission)) {
      fFileName.Form("%s/proof/etc/%s", confDir.Data(), fileName.Data());
      PDB(kGlobal,2)
         Info("GetWorkDir", "checking PROOF config file %s", fFileName.Data());
      if (gSystem->AccessPathName(fFileName, kReadPermission)) {
         Error("GetWorkDir", "no PROOF config file found");
         fValid = kFALSE;
         return kFALSE;
      }
   }

   // Open the config file
   fstream infile(fFileName.Data(), std::ios::in);
   if (infile.is_open()) {
      TProofNodeInfo *nodeinfo = 0;
      TString line = "";
      TString keyword = "";

      // Read the entire file into the allLines object
      TString allLines = "";
      allLines.ReadString(infile);
      TObjArray *lines = allLines.Tokenize("\n");
      Int_t numberOfLines = lines->GetEntries();

      // Process one line at the time
      for (Int_t j = 0; j < numberOfLines; j++) {
	 line = ((TObjString *)lines->At(j))->GetString();
         line = line.Strip(TString::kBoth);

         // Unless this line was empty or a comment, interpret the line
         if ( !((line(0,1) == "#") || (line == "")) ) {

            // Extract all words in the current line
            TObjArray *tokens = line.Tokenize(" ");
            Int_t n = tokens->GetEntries();
            TString option;
            TString value;
            for (Int_t i = 0; i < n; i++) {

               // Extrace one word from the current line
               keyword = ((TObjString *)tokens->At(i))->GetString();

               // Interpret this keyword
               switch (GetInfoType(keyword)) {
               case kNodeType: {
                  if (keyword == "master" || keyword == "node") {
                     nodeinfo = fMaster;
                     fFoundMaster = kTRUE;
                  }
                  break;
               }
               case kOption: {
                  // On what position is the '=' sign?
                  const Ssiz_t equalPosition =
                     keyword.Index("=", 1, 0, TString::kExact);

                  // Extract the option and its value
                  TString tmp = keyword;
                  option = tmp(0, equalPosition);

                  if ((option == "workdir") &&
                      (nodeinfo->fNodeType == TProofNodeInfo::GetNodeType("master"))) {
                     nodeinfo->fWorkDir = tmp(equalPosition + 1, tmp.Length());
                  }

                  break;
               }
               default:
                  break;
               } // end switch

            } // end if

         } // else

      } // while (! infile.eof() )

      // Did the config file contain appropriate master information?
      if (fFoundMaster) {
         // Set the work directory
         workDir = fMaster->GetWorkDir();
      } else {
         Error("ReadConfigFile","No master found in config file");
         fValid = kFALSE;
         status = kFALSE;
      }
   } // end if (infile.is_open())
   else {
      // Error: could not open file
      status = kFALSE;
      fValid = kFALSE;
   }

   infile.close();

   return (status ? workDir : "");
}

//______________________________________________________________________________
void TProofResourcesStatic::SetOption(TProofNodeInfo *nodeinfo,
                                      const TString &option,
                                      const TString &value)
{
   // Static method to set the node info options.

   if (option == "workdir") {
      nodeinfo->fWorkDir = value;
   } else if (option == "image") {
      nodeinfo->fImage = value;
   } else if (option == "perf") {
      nodeinfo->fPerfIndex = value.Atoi();
   } else if (option == "config") {
      nodeinfo->fConfig = value;
   } else if (option == "msd") {
      if (nodeinfo->fNodeType == TProofNodeInfo::GetNodeType("submaster")) {
         nodeinfo->fMsd = value;
      } else {
         ::Error("SetOption","msd only valid for submasters [ignored]");
      }
   } else if (option == "port") {
      nodeinfo->fPort = value.Atoi();
   } else {
      ::Error("SetOption","No such option [%s=%s]",option.Data(),value.Data());
   }
}

//______________________________________________________________________________
TProofResourcesStatic::EInfoType TProofResourcesStatic::GetInfoType(const TString &word)
{
   // Static method to determine the info type.

   EInfoType type = kNodeType;

   if ((word == "node") || (word == "master") || (word == "submaster") ||
       (word == "worker") || (word == "slave") ||
       (word == "condorworker") || (word == "condorslave")) {
      type = kNodeType;
   }
   else if (word.Contains("=", TString::kExact)) {
      type = kOption;
   } else {
      type = kHost;
   }

   return type;
}

//______________________________________________________________________________
TProofNodeInfo *TProofResourcesStatic::CreateNodeInfo(const TString &name)
{
   // Fill out the preliminary TProofNodeInfo structure.

   TProofNodeInfo *nodeInfo = new TProofNodeInfo();
   nodeInfo->fNodeType  = TProofNodeInfo::GetNodeType(name);
   nodeInfo->fNodeName  = name;
   nodeInfo->fPort      = -1;
   nodeInfo->fPerfIndex = 100;

   return nodeInfo;
}
<commit_msg>remove tab.<commit_after>// @(#)root/proof:$Name:  $:$Id: TProofResourcesStatic.cxx,v 1.1 2005/12/09 01:12:17 rdm Exp $
// Author: Paul Nilsson   7/12/2005

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TProofResourcesStatic                                                //
//                                                                      //
// Implementation of PROOF static resources.                            //
// The purpose of this class is to provide a standard interface to      //
// static config files. It interprets Proof config files (proof.conf)   //
// and sorts the contents into TProofNodeInfo objects. Master info will //
// be placed in fMaster (of type TProofNodeInfo). Submaster info will   //
// be put in fSubmasterList (a TList of TProofNodeInfo objects), while  //
// workers (and condorworkers) will be placed in fWorkerList (a TList   //
// of TProofNodeInfo objects).                                          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "Riostream.h"
#include "TProofResourcesStatic.h"
#include "TSystem.h"
#include "TProofServ.h"
#include "TProof.h"
#include "TInetAddress.h"
#include "TProofNodeInfo.h"
#include "TProofDebug.h"
#include "TUrl.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TError.h"

ClassImp(TProofResourcesStatic)

//______________________________________________________________________________
TProofResourcesStatic::TProofResourcesStatic()
{
   // This ctor is used in TProofServ::Setup() in combination with GetWorkDir()
   // for a quick scan of the config file to retrieve the work directory.

   // Create master node info and submaster/worker lists, and set default values
   InitResources();
}

//______________________________________________________________________________
TProofResourcesStatic::TProofResourcesStatic(const TString &confDir,
                                             const TString &fileName)
{
   // Using this ctor will retrieve all information in the config file
   // and store it in fMaster, fSubmasterList and fWorkerList,
   // condorworkers will be stored in the fWorkerList.

   // Create master node info and submaster/worker lists, and set default values
   InitResources();

   // Open and read the PROOF config file
   if (!ReadConfigFile(confDir, fileName)) {
      Error("TProofResourcesStatic", "error encountered while reading config file");
      fValid = kFALSE;
   }
}

//______________________________________________________________________________
TProofResourcesStatic::~TProofResourcesStatic()
{
   // Destructor.

   delete fSubmasterList;
   delete fWorkerList;
   delete fMaster;
}

//______________________________________________________________________________
void TProofResourcesStatic::InitResources()
{
   // Create master node info and submaster/worker lists,
   // and set default values.

   // Create master
   fMaster = new TProofNodeInfo();
   fMaster->fNodeType = TProofNodeInfo::GetNodeType("master");
   fFoundMaster = kFALSE; // Set to kTRUE if the config file contains master info

   // Create workers
   fWorkerList = new TList();
   fWorkerList->SetOwner();

   // Create submaster
   fSubmasterList = new TList();
   fSubmasterList->SetOwner();

   // Assume that the config file will be ok
   fValid = kTRUE;
}

//______________________________________________________________________________
TProofNodeInfo *TProofResourcesStatic::GetMaster()
{
   // Get the master node. Only return the master info if it was set
   // in the config file.

   if (fFoundMaster)
      return fMaster;

   return 0;
}

//______________________________________________________________________________
TList *TProofResourcesStatic::GetSubmasters()
{
   // Get the list of submaster nodes.

   return fSubmasterList;
}

//______________________________________________________________________________
TList *TProofResourcesStatic::GetWorkers(void)
{
   // Get the list of worker nodes.

   return fWorkerList;
}

//______________________________________________________________________________
Bool_t TProofResourcesStatic::ReadConfigFile(const TString &confDir,
                                             const TString &fileName)
{
   // Read the PROOF config file and fill the master and worker list.

   Bool_t status = kTRUE;

   PDB(kGlobal,1)
      Info("ReadConfigFile", "using PROOF config file: %s", fileName.Data());

   // Add a proper path to the file name
   fFileName.Form("%s/.%s", gSystem->Getenv("HOME"), fileName.Data());
   PDB(kGlobal,2)
      Info("ReadConfigFile", "checking PROOF config file %s", fFileName.Data());
   if (gSystem->AccessPathName(fFileName, kReadPermission)) {
      fFileName.Form("%s/proof/etc/%s", confDir.Data(), fileName.Data());
      PDB(kGlobal,2)
         Info("ReadConfigFile", "checking PROOF config file %s", fFileName.Data());
      if (gSystem->AccessPathName(fFileName, kReadPermission)) {
         Error("ReadConfigFile", "no PROOF config file found");
         return kFALSE;
      }
   }

   // Open the config file
   fstream infile(fFileName.Data(), std::ios::in);
   if (infile.is_open()) {
      Bool_t isMaster = kFALSE;
      Bool_t isSubmaster = kFALSE;
      Bool_t isWorker = kFALSE;

      // Each line in the file consists of several 'keywords', e.g.
      //   line = "master mypc image=local"
      //     keyword[0] = "master"
      //     keyword[1] = "mypc"
      //     keyword[2] = "image=local"
      // The last keyword has an option "image" with value "local"
      TString line = "";
      TString keyword = "";

      // Read the entire file into the allLines object
      TString allLines = "";
      allLines.ReadString(infile);
      TObjArray *lines = allLines.Tokenize("\n");
      Int_t numberOfLines = lines->GetEntries();

      // Process one line at the time
      for (Int_t j = 0; j < numberOfLines; j++) {
         TObjString *objLine = (TObjString *)lines->At(j);
         line = objLine->GetString();
         line = line.Strip(TString::kBoth);

         // Unless this line was empty or a comment, interpret the line
         if ( !((line(0,1) == "#") || (line == "")) ) {
            TProofNodeInfo *nodeinfo = 0;

            // Reset boolean (condorworkers are treated as a workers)
            isMaster = kFALSE;
            isSubmaster = kFALSE;
            isWorker = kFALSE;

            // Extract all words in the current line
            TObjArray *tokens = line.Tokenize(" ");
            Int_t n = tokens->GetEntries();
            TString option;
            TString value;
            for (Int_t i = 0; i < n; i++) {

               // Extrace one word from the current line
               keyword = ((TObjString *)tokens->At(i))->GetString();

               // Interpret this keyword
               switch (GetInfoType(keyword)) {
               case kNodeType: {
                  if (keyword == "master" || keyword == "node") {
                     nodeinfo = fMaster;
                     nodeinfo->fWorkDir = kPROOF_WorkDir;
                     isMaster = kTRUE;     // will be reset
                     fFoundMaster = kTRUE; // will not be reset
                  }
                  // [either submaster, worker or condorworker]
                  else if (keyword == "submaster") {
                     // Get a submaster info node
                     nodeinfo = CreateNodeInfo(keyword);
                     isSubmaster = kTRUE;
                  } else {
                     // Get a worker or condorworker info node
                     nodeinfo = CreateNodeInfo(keyword);
                     isWorker = kTRUE;
                  }
                  break;
               }
               case kHost: {
                  // Store the host name
                  if (nodeinfo) {
                     nodeinfo->fNodeName = keyword;

                     // Set default image
                     if (isMaster) {
                        TString node = TUrl(nodeinfo->fNodeName).GetHost();
                        nodeinfo->fImage = strstr(nodeinfo->fNodeName, node.Data());
                     } else {
                        // If the node name contains an '@' sign, it should be removed
                        // before copying it into the [default] image info
                        // On what position is the '@' sign? (if there is one)
                        TString tmp = nodeinfo->fNodeName;
                        const Ssiz_t equalPosition = tmp.Index("@", 1, 0, TString::kExact);

                        // Extract the host
                        nodeinfo->fImage = tmp(equalPosition + 1, tmp.Length());
                     }
                  } else {
                     Error("ReadConfigFile","Command not recognized: %s (ignored)",
                           keyword.Data());
                  }
                  break;
               }
               case kOption: {
                  // On what position is the '=' sign?
                  const Ssiz_t equalPosition =
                     keyword.Index("=", 1, 0, TString::kExact);

                  // Extract the option and its value
                  TString tmp = keyword;
                  option = tmp(0, equalPosition);
                  value = tmp(equalPosition + 1, tmp.Length());

                  // Set the node info options
                  SetOption(nodeinfo, option, value);
                  break;
               }
               default:
                  break;
               } // end switch

            } // end if

            // Store the submaster, worker or condorworker
            if (isWorker) {
               fWorkerList->Add(nodeinfo);
            }
            else if (isSubmaster) {
               fSubmasterList->Add(nodeinfo);
            }
         } // else

      } // while (! infile.eof() )
      infile.close();

      // Did the config file contain appropriate master information?
      if (!fFoundMaster) {
         Error("ReadConfigFile","No master info found in config file");
         status = kFALSE;
      } else {
         // Check if the master can run on this node
         TString node = TUrl(fMaster->fNodeName).GetHost();
         TString host = gSystem->GetHostByName(gSystem->HostName()).GetHostName();
         TInetAddress inetaddr = gSystem->GetHostByName(node);
         if ( !(!host.CompareTo(inetaddr.GetHostName()) || (node == "localhost")) ) {
            Error("ReadConfigFile","No appropriate master found in config file");
            status = kFALSE;
         }

         // Check the master work directory
         if (strcmp(gSystem->ExpandPathName(fMaster->GetWorkDir()),
                    gProofServ->GetWorkDir())) {
            Error("ReadConfigFile","Bad work directory: %s", fMaster->GetWorkDir().Data());
            status = kFALSE;
         }
      }
   } // end if (infile.is_open())
   else {
      // Error: could not open file
      status = kFALSE;
   }

   return status;
}

//______________________________________________________________________________
TString TProofResourcesStatic::GetWorkDir(const TString &confDir,
                                          const TString &fileName)
{
   // Read the working directory from the PROOF config file.
   // This method is used by TProofServ::Setup() rather than the full
   // interpretation of the config file as is done in ReadConfigFile().
   // If the workdir option is not specified in the config file,
   // GetWorkDir() will return an empty string.

   TString workDir;
   Bool_t status = kTRUE;

   PDB(kGlobal,1)
      Info("GetWorkDir", "using PROOF config file: %s", fileName.Data());

   // Add a proper path to the file name
   fFileName.Form("%s/.%s", gSystem->Getenv("HOME"), fileName.Data());
   PDB(kGlobal,2)
      Info("GetWorkDir", "checking PROOF config file %s", fFileName.Data());
   if (gSystem->AccessPathName(fFileName, kReadPermission)) {
      fFileName.Form("%s/proof/etc/%s", confDir.Data(), fileName.Data());
      PDB(kGlobal,2)
         Info("GetWorkDir", "checking PROOF config file %s", fFileName.Data());
      if (gSystem->AccessPathName(fFileName, kReadPermission)) {
         Error("GetWorkDir", "no PROOF config file found");
         fValid = kFALSE;
         return kFALSE;
      }
   }

   // Open the config file
   fstream infile(fFileName.Data(), std::ios::in);
   if (infile.is_open()) {
      TProofNodeInfo *nodeinfo = 0;
      TString line = "";
      TString keyword = "";

      // Read the entire file into the allLines object
      TString allLines = "";
      allLines.ReadString(infile);
      TObjArray *lines = allLines.Tokenize("\n");
      Int_t numberOfLines = lines->GetEntries();

      // Process one line at the time
      for (Int_t j = 0; j < numberOfLines; j++) {
         line = ((TObjString *)lines->At(j))->GetString();
         line = line.Strip(TString::kBoth);

         // Unless this line was empty or a comment, interpret the line
         if ( !((line(0,1) == "#") || (line == "")) ) {

            // Extract all words in the current line
            TObjArray *tokens = line.Tokenize(" ");
            Int_t n = tokens->GetEntries();
            TString option;
            TString value;
            for (Int_t i = 0; i < n; i++) {

               // Extrace one word from the current line
               keyword = ((TObjString *)tokens->At(i))->GetString();

               // Interpret this keyword
               switch (GetInfoType(keyword)) {
               case kNodeType: {
                  if (keyword == "master" || keyword == "node") {
                     nodeinfo = fMaster;
                     fFoundMaster = kTRUE;
                  }
                  break;
               }
               case kOption: {
                  // On what position is the '=' sign?
                  const Ssiz_t equalPosition =
                     keyword.Index("=", 1, 0, TString::kExact);

                  // Extract the option and its value
                  TString tmp = keyword;
                  option = tmp(0, equalPosition);

                  if ((option == "workdir") &&
                      (nodeinfo->fNodeType == TProofNodeInfo::GetNodeType("master"))) {
                     nodeinfo->fWorkDir = tmp(equalPosition + 1, tmp.Length());
                  }

                  break;
               }
               default:
                  break;
               } // end switch

            } // end if

         } // else

      } // while (! infile.eof() )

      // Did the config file contain appropriate master information?
      if (fFoundMaster) {
         // Set the work directory
         workDir = fMaster->GetWorkDir();
      } else {
         Error("ReadConfigFile","No master found in config file");
         fValid = kFALSE;
         status = kFALSE;
      }
   } // end if (infile.is_open())
   else {
      // Error: could not open file
      status = kFALSE;
      fValid = kFALSE;
   }

   infile.close();

   return (status ? workDir : "");
}

//______________________________________________________________________________
void TProofResourcesStatic::SetOption(TProofNodeInfo *nodeinfo,
                                      const TString &option,
                                      const TString &value)
{
   // Static method to set the node info options.

   if (option == "workdir") {
      nodeinfo->fWorkDir = value;
   } else if (option == "image") {
      nodeinfo->fImage = value;
   } else if (option == "perf") {
      nodeinfo->fPerfIndex = value.Atoi();
   } else if (option == "config") {
      nodeinfo->fConfig = value;
   } else if (option == "msd") {
      if (nodeinfo->fNodeType == TProofNodeInfo::GetNodeType("submaster")) {
         nodeinfo->fMsd = value;
      } else {
         ::Error("SetOption","msd only valid for submasters [ignored]");
      }
   } else if (option == "port") {
      nodeinfo->fPort = value.Atoi();
   } else {
      ::Error("SetOption","No such option [%s=%s]",option.Data(),value.Data());
   }
}

//______________________________________________________________________________
TProofResourcesStatic::EInfoType TProofResourcesStatic::GetInfoType(const TString &word)
{
   // Static method to determine the info type.

   EInfoType type = kNodeType;

   if ((word == "node") || (word == "master") || (word == "submaster") ||
       (word == "worker") || (word == "slave") ||
       (word == "condorworker") || (word == "condorslave")) {
      type = kNodeType;
   }
   else if (word.Contains("=", TString::kExact)) {
      type = kOption;
   } else {
      type = kHost;
   }

   return type;
}

//______________________________________________________________________________
TProofNodeInfo *TProofResourcesStatic::CreateNodeInfo(const TString &name)
{
   // Fill out the preliminary TProofNodeInfo structure.

   TProofNodeInfo *nodeInfo = new TProofNodeInfo();
   nodeInfo->fNodeType  = TProofNodeInfo::GetNodeType(name);
   nodeInfo->fNodeName  = name;
   nodeInfo->fPort      = -1;
   nodeInfo->fPerfIndex = 100;

   return nodeInfo;
}
<|endoftext|>