<commit_before>//==============================================================================
// Single cell simulation graph panels widget
//==============================================================================

#include "singlecellsimulationgraphpanel.h"
#include "singlecellsimulationgraphpanels.h"

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

#include <QSettings>
#include <QWheelEvent>

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

namespace OpenCOR {
namespace SingleCellSimulation {

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

SingleCellSimulationGraphPanels::SingleCellSimulationGraphPanels(const QString &pName,
                                                                 QWidget *pParent) :
    QSplitter(Qt::Vertical, pParent),
    CommonWidget(pName, this, pParent),
    mGraphPanelsCount(0)
{
}

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

static const QString SettingsGraphPanelsCount = "GraphPanelsCount";

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

void SingleCellSimulationGraphPanels::loadSettings(QSettings *pSettings)
{
    // Retrieve the number of graph panels (default: 1) and create the
    // corresponding number of graphs

    int graphPanelsCount = pSettings->value(SettingsGraphPanelsCount, 1).toInt();

    for (int i = 0; i < graphPanelsCount; ++i)
        addGraphPanel();

    // Select the first graph panel

    qobject_cast<SingleCellSimulationGraphPanel *>(widget(0))->setActive(true);
}

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

void SingleCellSimulationGraphPanels::saveSettings(QSettings *pSettings) const
{
    // Keep track of the number of graph panels

    pSettings->setValue(SettingsGraphPanelsCount, mGraphPanelsCount);
}

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

void SingleCellSimulationGraphPanels::wheelEvent(QWheelEvent *pEvent)
{
    // Default handling of the event

    QSplitter::wheelEvent(pEvent);

    // Select the previous/next graph panel, if any

    if (pEvent->delta())
    for (int i = 0, iMax = count(); i < iMax; ++i) {
        SingleCellSimulationGraphPanel *graphPanel = qobject_cast<SingleCellSimulationGraphPanel *>(widget(i));

        if (graphPanel->isActive()) {
            // We are dealing with the currently active graph panel, so
            // inactivate it and activate either its predecessor or successor

            graphPanel->setActive(false);

            i += (pEvent->delta() < 0)?1:-1;

            if (i < 0)
                i = 0;
            else if (i == iMax)
                i = iMax-1;

            qobject_cast<SingleCellSimulationGraphPanel *>(widget(i))->setActive(true);

            break;
        }
    }
}

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

SingleCellSimulationGraphPanel * SingleCellSimulationGraphPanels::addGraphPanel()
{
    // Check whether there is already a graph panel and if not, then delete our
    // dummy widget which ensures that we don't shrink

    if (!mGraphPanelsCount && count()) {
        // No previous graph panel, so...
        // Note: the test for count() above is for the very first time we want
        //       to add a graph panel and therefore where no dummy widget will
        //       be present...

        QWidget *dummyWidget = qobject_cast<QWidget*>(widget(0));

        dummyWidget->hide();

        delete dummyWidget;
    }

    // Create a new graph panel

    SingleCellSimulationGraphPanel *res = new SingleCellSimulationGraphPanel(this);

    // Add the graph panel to ourselves

    addWidget(res);

    // Keep track of the fact that we are holding one more graph panel

    ++mGraphPanelsCount;

    // Create a connection to keep track of whenever the graph panel gets
    // activated

    connect(res, SIGNAL(activated(SingleCellSimulationGraphPanel *)),
            this, SLOT(graphPanelActivated(SingleCellSimulationGraphPanel *)));

    // Activate it

    res->setActive(true);

    // Let people know that we have added a graph panel

    emit grapPanelAdded(res);

    // Return our newly created graph panel

    return res;
}

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

void SingleCellSimulationGraphPanels::removeGraphPanel()
{
    if (!mGraphPanelsCount)
        // We don't have any graph panel to remove, so...

        return;

    // Remove the current graph panel

    for (int i = 0, iMax = count(); i < iMax; ++i) {
        SingleCellSimulationGraphPanel *graphPanel = qobject_cast<SingleCellSimulationGraphPanel *>(widget(i));

        if (graphPanel->isActive()) {
            // We are dealing with the currently active graph panel, so remove
            // it

            graphPanel->hide();

            delete graphPanel;

            // Keep track of the fact that we are holding one less graph panel

            --mGraphPanelsCount;

            // Activate the next graph panel or the last one available, if any

            iMax = count();

            if (!iMax)
                // No more graph panel, so...

                break;
            else if (i < iMax)
                // There is a next graph panel, so activate it

                qobject_cast<SingleCellSimulationGraphPanel *>(widget(i))->setActive(true);
            else
                // We were dealing with the last graph panel, but there is still
                // at least one left, so activate the new last graph panel

                qobject_cast<SingleCellSimulationGraphPanel *>(widget(count()-1))->setActive(true);

            // We are all done, so...

            break;
        }
    }

    // Check whether we have any graph panel left and if so add a dummy widget
    // which will ensure that we don't shrink

    if (!mGraphPanelsCount)
        addWidget(new QWidget(this));

    // Let people know that we have removed a graph panel

    emit grapPanelRemoved();
}

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

int SingleCellSimulationGraphPanels::graphPanelsCount() const
{
    // Return the number of graph panels we currently hold

    return mGraphPanelsCount;
}

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

SingleCellSimulationGraphPanel * SingleCellSimulationGraphPanels::activeGraphPanel()
{
    // Return the active graph panel

    for (int i = 0, iMax = count(); i < iMax; ++i) {
        SingleCellSimulationGraphPanel *graphPanel = qobject_cast<SingleCellSimulationGraphPanel *>(widget(i));

        if (graphPanel->isActive())
            // We found the active graph panel, so...

            return graphPanel;
    }

    // There are no graph panels, so...
    // Note: indeed, since if there is at least one graph panel, then we have an
    //       active graph panel...

    return 0;
}

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

void SingleCellSimulationGraphPanels::graphPanelActivated(SingleCellSimulationGraphPanel *pGraphPanel)
{
    // A graph panel has been activated, so inactivate all the others

    for (int i = 0, iMax = count(); i < iMax; ++i) {
        SingleCellSimulationGraphPanel *graphPanel = qobject_cast<SingleCellSimulationGraphPanel *>(widget(i));

        if (graphPanel != pGraphPanel)
            // We are not dealing with the graph panel that just got activated,
            // so inactivate it

            graphPanel->setActive(false);
    }
}

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

}   // namespace SingleCellSimulation
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Closes #54 (again!).<commit_after>//==============================================================================
// Single cell simulation graph panels widget
//==============================================================================

#include "singlecellsimulationgraphpanel.h"
#include "singlecellsimulationgraphpanels.h"

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

#include <QSettings>
#include <QWheelEvent>

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

namespace OpenCOR {
namespace SingleCellSimulation {

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

SingleCellSimulationGraphPanels::SingleCellSimulationGraphPanels(const QString &pName,
                                                                 QWidget *pParent) :
    QSplitter(Qt::Vertical, pParent),
    CommonWidget(pName, this, pParent),
    mGraphPanelsCount(0)
{
}

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

static const QString SettingsGraphPanelsCount = "GraphPanelsCount";

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

void SingleCellSimulationGraphPanels::loadSettings(QSettings *pSettings)
{
    // Retrieve the number of graph panels (default: 1) and create the
    // corresponding number of graphs

    int graphPanelsCount = pSettings->value(SettingsGraphPanelsCount, 1).toInt();

    for (int i = 0; i < graphPanelsCount; ++i)
        addGraphPanel();

    // Select the first graph panel

    qobject_cast<SingleCellSimulationGraphPanel *>(widget(0))->setActive(true);
}

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

void SingleCellSimulationGraphPanels::saveSettings(QSettings *pSettings) const
{
    // Keep track of the number of graph panels

    pSettings->setValue(SettingsGraphPanelsCount, mGraphPanelsCount);
}

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

void SingleCellSimulationGraphPanels::wheelEvent(QWheelEvent *pEvent)
{
    // Default handling of the event

    QSplitter::wheelEvent(pEvent);

    // Select the previous/next graph panel, if any

    if (pEvent->delta())
    for (int i = 0, iMax = count(); i < iMax; ++i) {
        SingleCellSimulationGraphPanel *graphPanel = qobject_cast<SingleCellSimulationGraphPanel *>(widget(i));

        if (graphPanel->isActive()) {
            // We are dealing with the currently active graph panel, so
            // inactivate it and activate either its predecessor or successor

            graphPanel->setActive(false);

#ifdef Q_WS_MAC
            i -= (pEvent->delta() < 0)?1:-1;
#else
            i += (pEvent->delta() < 0)?1:-1;
#endif

            if (i < 0)
                i = 0;
            else if (i == iMax)
                i = iMax-1;

            qobject_cast<SingleCellSimulationGraphPanel *>(widget(i))->setActive(true);

            break;
        }
    }
}

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

SingleCellSimulationGraphPanel * SingleCellSimulationGraphPanels::addGraphPanel()
{
    // Check whether there is already a graph panel and if not, then delete our
    // dummy widget which ensures that we don't shrink

    if (!mGraphPanelsCount && count()) {
        // No previous graph panel, so...
        // Note: the test for count() above is for the very first time we want
        //       to add a graph panel and therefore where no dummy widget will
        //       be present...

        QWidget *dummyWidget = qobject_cast<QWidget*>(widget(0));

        dummyWidget->hide();

        delete dummyWidget;
    }

    // Create a new graph panel

    SingleCellSimulationGraphPanel *res = new SingleCellSimulationGraphPanel(this);

    // Add the graph panel to ourselves

    addWidget(res);

    // Keep track of the fact that we are holding one more graph panel

    ++mGraphPanelsCount;

    // Create a connection to keep track of whenever the graph panel gets
    // activated

    connect(res, SIGNAL(activated(SingleCellSimulationGraphPanel *)),
            this, SLOT(graphPanelActivated(SingleCellSimulationGraphPanel *)));

    // Activate it

    res->setActive(true);

    // Let people know that we have added a graph panel

    emit grapPanelAdded(res);

    // Return our newly created graph panel

    return res;
}

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

void SingleCellSimulationGraphPanels::removeGraphPanel()
{
    if (!mGraphPanelsCount)
        // We don't have any graph panel to remove, so...

        return;

    // Remove the current graph panel

    for (int i = 0, iMax = count(); i < iMax; ++i) {
        SingleCellSimulationGraphPanel *graphPanel = qobject_cast<SingleCellSimulationGraphPanel *>(widget(i));

        if (graphPanel->isActive()) {
            // We are dealing with the currently active graph panel, so remove
            // it

            graphPanel->hide();

            delete graphPanel;

            // Keep track of the fact that we are holding one less graph panel

            --mGraphPanelsCount;

            // Activate the next graph panel or the last one available, if any

            iMax = count();

            if (!iMax)
                // No more graph panel, so...

                break;
            else if (i < iMax)
                // There is a next graph panel, so activate it

                qobject_cast<SingleCellSimulationGraphPanel *>(widget(i))->setActive(true);
            else
                // We were dealing with the last graph panel, but there is still
                // at least one left, so activate the new last graph panel

                qobject_cast<SingleCellSimulationGraphPanel *>(widget(count()-1))->setActive(true);

            // We are all done, so...

            break;
        }
    }

    // Check whether we have any graph panel left and if so add a dummy widget
    // which will ensure that we don't shrink

    if (!mGraphPanelsCount)
        addWidget(new QWidget(this));

    // Let people know that we have removed a graph panel

    emit grapPanelRemoved();
}

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

int SingleCellSimulationGraphPanels::graphPanelsCount() const
{
    // Return the number of graph panels we currently hold

    return mGraphPanelsCount;
}

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

SingleCellSimulationGraphPanel * SingleCellSimulationGraphPanels::activeGraphPanel()
{
    // Return the active graph panel

    for (int i = 0, iMax = count(); i < iMax; ++i) {
        SingleCellSimulationGraphPanel *graphPanel = qobject_cast<SingleCellSimulationGraphPanel *>(widget(i));

        if (graphPanel->isActive())
            // We found the active graph panel, so...

            return graphPanel;
    }

    // There are no graph panels, so...
    // Note: indeed, since if there is at least one graph panel, then we have an
    //       active graph panel...

    return 0;
}

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

void SingleCellSimulationGraphPanels::graphPanelActivated(SingleCellSimulationGraphPanel *pGraphPanel)
{
    // A graph panel has been activated, so inactivate all the others

    for (int i = 0, iMax = count(); i < iMax; ++i) {
        SingleCellSimulationGraphPanel *graphPanel = qobject_cast<SingleCellSimulationGraphPanel *>(widget(i));

        if (graphPanel != pGraphPanel)
            // We are not dealing with the graph panel that just got activated,
            // so inactivate it

            graphPanel->setActive(false);
    }
}

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

}   // namespace SingleCellSimulation
}   // namespace OpenCOR

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


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXQt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012-2013 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include <QDir>

#include "lxqtapplication.h"
#include "lxqtsettings.h"

#include <XdgDirs>

using namespace LXQt;

#define COLOR_DEBUG "\033[32;2m"
#define COLOR_WARN "\033[33;2m"
#define COLOR_CRITICAL "\033[31;1m"
#define COLOR_FATAL "\033[33;1m"
#define COLOR_RESET "\033[0m"

#define QAPP_NAME qApp ? qApp->objectName().toUtf8().constData() : ""

#include <cstdio>
#include <unistd.h>
#include <cstring>
#include <csignal>
#include <sys/socket.h>
#include <QDateTime>
#include <QDebug>
#include <QSocketNotifier>
/*! \brief Log qDebug input to file
Used only in pure Debug builds or when is the system environment
variable LXQT_DEBUG set
*/
void dbgMessageOutput(QtMsgType type, const QMessageLogContext &ctx, const QString & msgStr)
{
    QByteArray msgBuf = msgStr.toUtf8();
    const char* msg = msgBuf.constData();
    QDir dir(XdgDirs::configHome().toUtf8() + QLatin1String("/lxqt"));
    dir.mkpath(".");

    const char* typestr;
    const char* color;
    switch (type) {
    case QtDebugMsg:
        typestr = "Debug";
        color = COLOR_DEBUG;
        break;
    case QtWarningMsg:
        typestr = "Warning";
        color = COLOR_WARN;
        break;
    case QtFatalMsg:
        typestr = "Fatal";
        color = COLOR_FATAL;
        break;
    default: // QtCriticalMsg
        typestr = "Critical";
        color = COLOR_CRITICAL;
    }

    QByteArray dt = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toUtf8();
    if (isatty(STDERR_FILENO))
        fprintf(stderr, "%s %s(%p) %s: %s%s\n", color, QAPP_NAME, qApp, typestr, msg, COLOR_RESET);
    else
        fprintf(stderr, "%s(%p) %s: %s\n", QAPP_NAME, qApp, typestr, msg);

    FILE *f = fopen(dir.absoluteFilePath("debug.log").toUtf8().constData(), "a+");
    fprintf(f, "%s %s(%p) %s: %s\n", dt.constData(), QAPP_NAME, qApp, typestr, msg);
    fclose(f);

    if (type == QtFatalMsg)
        abort();
}

Application::Application(int &argc, char** argv)
    : QApplication(argc, argv)
{
#ifdef DEBUG
    qInstallMessageHandler(dbgMessageOutput);
#else
    if (!qgetenv("LXQT_DEBUG").isNull())
        qInstallMessageHandler(dbgMessageOutput);
#endif

    setWindowIcon(QIcon(QString(LXQT_GRAPHICS_DIR) + "/lxqt_logo.png"));
    connect(Settings::globalSettings(), SIGNAL(lxqtThemeChanged()), this, SLOT(updateTheme()));
    updateTheme();
}

Application::Application(int &argc, char** argv, bool handleQuitSignals)
    : Application(argc, argv)
{
    if (handleQuitSignals)
    {
        QList<int> signo_list = {SIGINT, SIGTERM, SIGHUP};
        connect(this, &Application::unixSignal, [this, signo_list] (int signo)
            {
                if (signo_list.contains(signo))
                    quit();
            });
        listenToUnixSignals(signo_list);
    }
}

void Application::updateTheme()
{
    QString styleSheetKey = QFileInfo(applicationFilePath()).fileName();
    setStyleSheet(lxqtTheme.qss(styleSheetKey));
    emit themeChanged();
}

namespace
{
    int signal_sock[2];

    void signalHandler(int signo)
    {
        int ret = write(signal_sock[0], &signo, sizeof (int));
        if (sizeof (int) != ret)
            qCritical() << QStringLiteral("unable to write into socketpair, %1").arg(strerror(errno));
    }
}

void Application::listenToUnixSignals(QList<int> const & signoList)
{
    static QSocketNotifier * signal_notifier = nullptr;

    if (nullptr == signal_notifier)
    {
        if (0 != socketpair(AF_UNIX, SOCK_STREAM, 0, signal_sock))
        {
            qCritical() << QStringLiteral("unable to create socketpair for correct signal handling: %1)").arg(strerror(errno));
            return;
        }

        signal_notifier = new QSocketNotifier(signal_sock[1], QSocketNotifier::Read, this);
        connect(signal_notifier, &QSocketNotifier::activated, [this] {
                int signo = 0;
                int ret = read(signal_sock[1], &signo, sizeof (int));
                if (sizeof (int) != ret)
                    qCritical() << QStringLiteral("unable to read signal from socketpair, %1").arg(strerror(errno));
                emit unixSignal(signo);
                });
    }

    struct sigaction sa;
    sa.sa_handler = signalHandler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    for (auto const & signo : signoList)
        sigaction(signo, &sa, nullptr);
}
<commit_msg>application: Correct signal handling & clean-up (#72)<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXQt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012-2013 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include <QDir>

#include "lxqtapplication.h"
#include "lxqtsettings.h"

#include <XdgDirs>

using namespace LXQt;

#define COLOR_DEBUG "\033[32;2m"
#define COLOR_WARN "\033[33;2m"
#define COLOR_CRITICAL "\033[31;1m"
#define COLOR_FATAL "\033[33;1m"
#define COLOR_RESET "\033[0m"

#define QAPP_NAME qApp ? qApp->objectName().toUtf8().constData() : ""

#include <cstdio>
#include <unistd.h>
#include <cstring>
#include <csignal>
#include <sys/socket.h>
#include <QDateTime>
#include <QDebug>
#include <QSocketNotifier>
/*! \brief Log qDebug input to file
Used only in pure Debug builds or when is the system environment
variable LXQT_DEBUG set
*/
void dbgMessageOutput(QtMsgType type, const QMessageLogContext &ctx, const QString & msgStr)
{
    QByteArray msgBuf = msgStr.toUtf8();
    const char* msg = msgBuf.constData();
    QDir dir(XdgDirs::configHome().toUtf8() + QLatin1String("/lxqt"));
    dir.mkpath(".");

    const char* typestr;
    const char* color;
    switch (type) {
    case QtDebugMsg:
        typestr = "Debug";
        color = COLOR_DEBUG;
        break;
    case QtWarningMsg:
        typestr = "Warning";
        color = COLOR_WARN;
        break;
    case QtFatalMsg:
        typestr = "Fatal";
        color = COLOR_FATAL;
        break;
    default: // QtCriticalMsg
        typestr = "Critical";
        color = COLOR_CRITICAL;
    }

    QByteArray dt = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toUtf8();
    if (isatty(STDERR_FILENO))
        fprintf(stderr, "%s %s(%p) %s: %s%s\n", color, QAPP_NAME, qApp, typestr, msg, COLOR_RESET);
    else
        fprintf(stderr, "%s(%p) %s: %s\n", QAPP_NAME, qApp, typestr, msg);

    FILE *f = fopen(dir.absoluteFilePath("debug.log").toUtf8().constData(), "a+");
    fprintf(f, "%s %s(%p) %s: %s\n", dt.constData(), QAPP_NAME, qApp, typestr, msg);
    fclose(f);

    if (type == QtFatalMsg)
        abort();
}

Application::Application(int &argc, char** argv)
    : QApplication(argc, argv)
{
#ifdef DEBUG
    qInstallMessageHandler(dbgMessageOutput);
#else
    if (!qgetenv("LXQT_DEBUG").isNull())
        qInstallMessageHandler(dbgMessageOutput);
#endif

    setWindowIcon(QIcon(QString(LXQT_GRAPHICS_DIR) + "/lxqt_logo.png"));
    connect(Settings::globalSettings(), SIGNAL(lxqtThemeChanged()), this, SLOT(updateTheme()));
    updateTheme();
}

Application::Application(int &argc, char** argv, bool handleQuitSignals)
    : Application(argc, argv)
{
    if (handleQuitSignals)
    {
        QList<int> signo_list = {SIGINT, SIGTERM, SIGHUP};
        connect(this, &Application::unixSignal, [this, signo_list] (int signo)
            {
                if (signo_list.contains(signo))
                    quit();
            });
        listenToUnixSignals(signo_list);
    }
}

void Application::updateTheme()
{
    QString styleSheetKey = QFileInfo(applicationFilePath()).fileName();
    setStyleSheet(lxqtTheme.qss(styleSheetKey));
    emit themeChanged();
}

namespace
{
    class SignalHandler
    {
    public:
        static void signalHandler(int signo)
        {
            int ret = write(instance->mSignalSock[0], &signo, sizeof (int));
            if (sizeof (int) != ret)
                qCritical() << QStringLiteral("unable to write into socketpair, %1").arg(strerror(errno));
        }

    public:
        template <class Lambda>
        SignalHandler(Lambda signalEmitter)
            : mSignalSock{-1, -1}
        {
            if (0 != socketpair(AF_UNIX, SOCK_STREAM, 0, mSignalSock))
            {
                qCritical() << QStringLiteral("unable to create socketpair for correct signal handling: %1)").arg(strerror(errno));
                return;
            }

            mNotifier.reset(new QSocketNotifier(mSignalSock[1], QSocketNotifier::Read));
            QObject::connect(mNotifier.data(), &QSocketNotifier::activated, [this, signalEmitter] {
                int signo = 0;
                int ret = read(mSignalSock[1], &signo, sizeof (int));
                if (sizeof (int) != ret)
                qCritical() << QStringLiteral("unable to read signal from socketpair, %1").arg(strerror(errno));
                signalEmitter(signo);
            });
        }

        ~SignalHandler()
        {
            close(mSignalSock[0]);
            close(mSignalSock[1]);
        }

        void listenToSignals(QList<int> const & signoList)
        {
            struct sigaction sa;
            sa.sa_handler = signalHandler;
            sigemptyset(&sa.sa_mask);
            sa.sa_flags = 0;
            for (auto const & signo : signoList)
                sigaction(signo, &sa, nullptr);
        }

    public:
        static QScopedPointer<SignalHandler> instance;

    private:
        int mSignalSock[2];
        QScopedPointer<QSocketNotifier> mNotifier;
    };

    QScopedPointer<SignalHandler> SignalHandler::instance;
}

void Application::listenToUnixSignals(QList<int> const & signoList)
{
    static QScopedPointer<QSocketNotifier> signal_notifier;

    if (SignalHandler::instance.isNull())
        SignalHandler::instance.reset(new SignalHandler{[this] (int signo) { emit unixSignal(signo); }});
    SignalHandler::instance->listenToSignals(signoList);
}
<|endoftext|>


<commit_before>#include <QImage>
#include "raster.h"
#include "pixeliterator.h"
#include "rootdrawer.h"
#include "factory.h"
#include "abstractfactory.h"
#include "drawers/rasterimagefactory.h"
#include "drawers/attributevisualproperties.h"

#include "rastervalueimage.h"

using namespace Ilwis;
using namespace Geodrawer;

REGISTER_RASTERIMAGETYPE(RasterValueImage,itNUMERICDOMAIN);

RasterValueImage::RasterValueImage(DrawerInterface *rootDrawer, const IRasterCoverage& raster, const VisualAttribute &vattribute,const IOOptions &options) :
    RasterImage(rootDrawer,raster,vattribute, options)
{
}

RasterValueImage::~RasterValueImage()
{

}

RasterImage *RasterValueImage::create(DrawerInterface *rootDrawer, const IRasterCoverage& raster, const VisualAttribute &vattribute,const IOOptions &options)
{
    return new RasterValueImage(rootDrawer, raster, vattribute, options)    ;
}

bool RasterValueImage::prepare(int prepareType)
{
    bool resetImage = false;
    BoundingBox bb(_raster->size());
    int xl = (quint32)bb.xlength() % 4 == 0 ? bb.xlength() : (((quint32)bb.xlength() / 4) + 1) * 4;
    int rest = xl - bb.xlength();
    if ( hasType(prepareType, DrawerInterface::ptRENDER)){
        std::vector<QColor> colors = _visualAttribute.colors();
        _colorTable = QVector<QRgb>(colors.size()) ;
        for(int i = 0; i < _colorTable.size(); ++i)
            _colorTable[i] = colors[i].rgba();
        resetImage = true;

    }

    if ( hasType(prepareType, DrawerInterface::ptGEOMETRY)){
        quint32 size = xl * bb.ylength();
        _pixels.resize(size);
        PixelIterator pixIter(_raster);

        SPNumericRange numrange =  _raster->datadef().range<NumericRange>();
        auto end = pixIter.end();
        quint32 position = 0;
        while(pixIter != end){
            double value = *pixIter;
            int index = value == rUNDEF ? 0 : 1 + (_colorTable.size() - 1) * (value - numrange->min()) / numrange->distance();
            _pixels[position] = index;
            ++pixIter;
            if ( pixIter.ychanged()){
                position += rest;
            }
            ++position;
        }
        resetImage = true;
    }

    if ( resetImage)   {
        const uchar *datablock = (const uchar *)_pixels.data();
        _image.reset(new QImage(datablock,xl, bb.ylength(),QImage::Format_Indexed8));
        _image->setColorTable(_colorTable);
    }
    return resetImage;

}

<commit_msg>comments<commit_after>#include <QImage>
#include "raster.h"
#include "pixeliterator.h"
#include "rootdrawer.h"
#include "factory.h"
#include "abstractfactory.h"
#include "drawers/rasterimagefactory.h"
#include "drawers/attributevisualproperties.h"

#include "rastervalueimage.h"

using namespace Ilwis;
using namespace Geodrawer;

REGISTER_RASTERIMAGETYPE(RasterValueImage,itNUMERICDOMAIN);

RasterValueImage::RasterValueImage(DrawerInterface *rootDrawer, const IRasterCoverage& raster, const VisualAttribute &vattribute,const IOOptions &options) :
    RasterImage(rootDrawer,raster,vattribute, options)
{
}

RasterValueImage::~RasterValueImage()
{

}

RasterImage *RasterValueImage::create(DrawerInterface *rootDrawer, const IRasterCoverage& raster, const VisualAttribute &vattribute,const IOOptions &options)
{
    return new RasterValueImage(rootDrawer, raster, vattribute, options)    ;
}

bool RasterValueImage::prepare(int prepareType)
{
    bool resetImage = false;
    BoundingBox bb(_raster->size());
    // lines must be 32 bit alligned. an entry pixel is a byte, so everything must be 4 alligned (32 bit is 4 bytes)
    int xl = (quint32)bb.xlength() % 4 == 0 ? bb.xlength() : (((quint32)bb.xlength() / 4) + 1) * 4;
    int rest = xl - bb.xlength();
    if ( hasType(prepareType, DrawerInterface::ptRENDER)){
        std::vector<QColor> colors = _visualAttribute.colors();
        _colorTable = QVector<QRgb>(colors.size()) ;
        for(int i = 0; i < _colorTable.size(); ++i)
            _colorTable[i] = colors[i].rgba();
        resetImage = true;

    }

    if ( hasType(prepareType, DrawerInterface::ptGEOMETRY)){
        quint32 size = xl * bb.ylength();
        _pixels.resize(size);
        PixelIterator pixIter(_raster);

        SPNumericRange numrange =  _raster->datadef().range<NumericRange>();
        auto end = pixIter.end();
        quint32 position = 0;
        while(pixIter != end){
            double value = *pixIter;
            int index = value == rUNDEF ? 0 : 1 + (_colorTable.size() - 1) * (value - numrange->min()) / numrange->distance();
            _pixels[position] = index;
            ++pixIter;
            if ( pixIter.ychanged()){
                position += rest;
            }
            ++position;
        }
        resetImage = true;
    }

    if ( resetImage)   {
        const uchar *datablock = (const uchar *)_pixels.data();
        _image.reset(new QImage(datablock,xl, bb.ylength(),QImage::Format_Indexed8));
        _image->setColorTable(_colorTable);
    }
    return resetImage;

}

<|endoftext|>


<commit_before>//===--- DiagnosticConsumer.cpp - Diagnostic Consumer Impl ----------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements the DiagnosticConsumer class.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "swift-ast"
#include "swift/AST/DiagnosticConsumer.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/SourceManager.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;

DiagnosticConsumer::~DiagnosticConsumer() = default;

llvm::SMLoc DiagnosticConsumer::getRawLoc(SourceLoc loc) {
  return loc.Value;
}

LLVM_ATTRIBUTE_UNUSED
static bool hasDuplicateFileNames(
    ArrayRef<FileSpecificDiagnosticConsumer::ConsumerPair> consumers) {
  llvm::StringSet<> seenFiles;
  for (const auto &consumerPair : consumers) {
    if (consumerPair.first.empty()) {
      // We can handle multiple consumers that aren't associated with any file,
      // because they only collect diagnostics that aren't in any of the special
      // files. This isn't an important use case to support, but also SmallSet
      // doesn't handle empty strings anyway!
      continue;
    }

    bool isUnique = seenFiles.insert(consumerPair.first).second;
    if (!isUnique)
      return true;
  }
  return false;
}

FileSpecificDiagnosticConsumer::FileSpecificDiagnosticConsumer(
    SmallVectorImpl<ConsumerPair> &consumers)
  : SubConsumers(std::move(consumers)) {
  assert(!SubConsumers.empty() &&
         "don't waste time handling diagnostics that will never get emitted");
  assert(!hasDuplicateFileNames(SubConsumers) &&
         "having multiple consumers for the same file is not implemented");
}

void FileSpecificDiagnosticConsumer::computeConsumersOrderedByRange(
    SourceManager &SM) {
  // Look up each file's source range and add it to the "map" (to be sorted).
  for (const ConsumerPair &pair : SubConsumers) {
    if (pair.first.empty())
      continue;

    Optional<unsigned> bufferID = SM.getIDForBufferIdentifier(pair.first);
    assert(bufferID.hasValue() && "consumer registered for unknown file");
    CharSourceRange range = SM.getRangeForBuffer(bufferID.getValue());
    ConsumersOrderedByRange.emplace_back(
        ConsumerSpecificInformation(range, pair.second.get()));
  }

  // Sort the "map" by buffer /end/ location, for use with std::lower_bound
  // later. (Sorting by start location would produce the same sort, since the
  // ranges must not be overlapping, but since we need to check end locations
  // later it's consistent to sort by that here.)
  std::sort(ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(),
            [](const ConsumerSpecificInformation &left,
               const ConsumerSpecificInformation &right) -> bool {
              auto compare = std::less<const char *>();
              return compare(getRawLoc(left.range.getEnd()).getPointer(),
                             getRawLoc(right.range.getEnd()).getPointer());
            });

  // Check that the ranges are non-overlapping. If the files really are all
  // distinct, this should be trivially true, but if it's ever not we might end
  // up mis-filing diagnostics.
  assert(ConsumersOrderedByRange.end() ==
             std::adjacent_find(ConsumersOrderedByRange.begin(),
                                ConsumersOrderedByRange.end(),
                                [](const ConsumerSpecificInformation &left,
                                   const ConsumerSpecificInformation &right) {
                                  return left.range.overlaps(right.range);
                                }) &&
         "overlapping ranges despite having distinct files");
}

Optional<FileSpecificDiagnosticConsumer::ConsumerSpecificInformation *>
FileSpecificDiagnosticConsumer::consumerSpecificInformationForLocation(
    SourceManager &SM, SourceLoc loc) const {
  // Diagnostics with invalid locations always go to every consumer.
  if (loc.isInvalid())
    return None;

  // This map is generated on first use and cached, to allow the
  // FileSpecificDiagnosticConsumer to be set up before the source files are
  // actually loaded.
  if (ConsumersOrderedByRange.empty()) {

    // It's possible to get here while a bridging header PCH is being
    // attached-to, if there's some sort of AST-reader warning or error, which
    // happens before CompilerInstance::setUpInputs(), at which point _no_
    // source buffers are loaded in yet. In that case we return None, rather
    // than trying to build a nonsensical map (and actually crashing since we
    // can't find buffers for the inputs).
    assert(!SubConsumers.empty());
    if (!SM.getIDForBufferIdentifier(SubConsumers.begin()->first).hasValue()) {
      assert(llvm::none_of(SubConsumers, [&](const ConsumerPair &pair) {
            return SM.getIDForBufferIdentifier(pair.first).hasValue();
          }));
      return None;
    }
    auto *mutableThis = const_cast<FileSpecificDiagnosticConsumer*>(this);
    mutableThis->computeConsumersOrderedByRange(SM);
  }

  // This std::lower_bound call is doing a binary search for the first range
  // that /might/ contain 'loc'. Specifically, since the ranges are sorted
  // by end location, it's looking for the first range where the end location
  // is greater than or equal to 'loc'.
  const ConsumerSpecificInformation *possiblyContainingRangeIter =
      std::lower_bound(
          ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(), loc,
          [](const ConsumerSpecificInformation &entry, SourceLoc loc) -> bool {
            auto compare = std::less<const char *>();
            return compare(getRawLoc(entry.range.getEnd()).getPointer(),
                           getRawLoc(loc).getPointer());
          });

  if (possiblyContainingRangeIter != ConsumersOrderedByRange.end() &&
      possiblyContainingRangeIter->range.contains(loc)) {
    return const_cast<ConsumerSpecificInformation *>(
        possiblyContainingRangeIter);
  }

  return None;
}

void FileSpecificDiagnosticConsumer::handleDiagnostic(
    SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind,
    StringRef FormatString, ArrayRef<DiagnosticArgument> FormatArgs,
    const DiagnosticInfo &Info) {

  HasAnErrorBeenConsumed |= Kind == DiagnosticKind::Error;

  Optional<ConsumerSpecificInformation *> consumerSpecificInfo;
  switch (Kind) {
  case DiagnosticKind::Error:
  case DiagnosticKind::Warning:
  case DiagnosticKind::Remark:
    consumerSpecificInfo = consumerSpecificInformationForLocation(SM, Loc);
    ConsumerSpecificInfoForSubsequentNotes = consumerSpecificInfo;
    break;
  case DiagnosticKind::Note:
    consumerSpecificInfo = ConsumerSpecificInfoForSubsequentNotes;
    break;
  }
  if (!consumerSpecificInfo.hasValue()) {
    for (auto &subConsumer : SubConsumers) {
      if (subConsumer.second) {
        subConsumer.second->handleDiagnostic(SM, Loc, Kind, FormatString,
                                             FormatArgs, Info);
      }
    }
    return;
  }
  if (!consumerSpecificInfo.getValue()->consumer)
    return; // Suppress non-primary diagnostic in batch mode.

  consumerSpecificInfo.getValue()->consumer->handleDiagnostic(
      SM, Loc, Kind, FormatString, FormatArgs, Info);
  consumerSpecificInfo.getValue()->hasAnErrorBeenEmitted |=
      Kind == DiagnosticKind::Error;
}

bool FileSpecificDiagnosticConsumer::finishProcessing(SourceManager &SM) {
  addNonSpecificErrors(SM);

  // Deliberately don't use std::any_of here because we don't want early-exit
  // behavior.

  bool hadError = false;
  for (auto &subConsumer : SubConsumers)
    hadError |= subConsumer.second && subConsumer.second->finishProcessing(SM);
  return hadError;
}

static void produceNonSpecificError(
    FileSpecificDiagnosticConsumer::ConsumerSpecificInformation &info,
    SourceManager &SM) {
  Diagnostic diagnostic(
      diag::error_compilation_stopped_by_errors_in_other_files);

  // Stolen from DiagnosticEngine::emitDiagnostic
  DiagnosticInfo Info;
  Info.ID = diagnostic.getID();

  info.consumer->handleDiagnostic(
      SM, info.range.getStart(), DiagnosticKind::Error,
      DiagnosticEngine::diagnosticStringFor(diagnostic.getID()), {}, Info);
}

void FileSpecificDiagnosticConsumer::addNonSpecificErrors(SourceManager &SM) {
  if (!HasAnErrorBeenConsumed)
    return;
  for (auto &info : ConsumersOrderedByRange) {
    if (!info.hasAnErrorBeenEmitted && info.consumer) {
      produceNonSpecificError(info, SM);
      info.hasAnErrorBeenEmitted = true;
    }
  }
}

void NullDiagnosticConsumer::handleDiagnostic(
    SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind,
    StringRef FormatString, ArrayRef<DiagnosticArgument> FormatArgs,
    const DiagnosticInfo &Info) {
  DEBUG({
    llvm::dbgs() << "NullDiagnosticConsumer received diagnostic: ";
    DiagnosticEngine::formatDiagnosticText(llvm::dbgs(), FormatString,
                                           FormatArgs);
    llvm::dbgs() << "\n";
  });
}
<commit_msg>Rename info to consumerInfo to be less confusable with Info in procedNonSpecificError.<commit_after>//===--- DiagnosticConsumer.cpp - Diagnostic Consumer Impl ----------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements the DiagnosticConsumer class.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "swift-ast"
#include "swift/AST/DiagnosticConsumer.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/SourceManager.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;

DiagnosticConsumer::~DiagnosticConsumer() = default;

llvm::SMLoc DiagnosticConsumer::getRawLoc(SourceLoc loc) {
  return loc.Value;
}

LLVM_ATTRIBUTE_UNUSED
static bool hasDuplicateFileNames(
    ArrayRef<FileSpecificDiagnosticConsumer::ConsumerPair> consumers) {
  llvm::StringSet<> seenFiles;
  for (const auto &consumerPair : consumers) {
    if (consumerPair.first.empty()) {
      // We can handle multiple consumers that aren't associated with any file,
      // because they only collect diagnostics that aren't in any of the special
      // files. This isn't an important use case to support, but also SmallSet
      // doesn't handle empty strings anyway!
      continue;
    }

    bool isUnique = seenFiles.insert(consumerPair.first).second;
    if (!isUnique)
      return true;
  }
  return false;
}

FileSpecificDiagnosticConsumer::FileSpecificDiagnosticConsumer(
    SmallVectorImpl<ConsumerPair> &consumers)
  : SubConsumers(std::move(consumers)) {
  assert(!SubConsumers.empty() &&
         "don't waste time handling diagnostics that will never get emitted");
  assert(!hasDuplicateFileNames(SubConsumers) &&
         "having multiple consumers for the same file is not implemented");
}

void FileSpecificDiagnosticConsumer::computeConsumersOrderedByRange(
    SourceManager &SM) {
  // Look up each file's source range and add it to the "map" (to be sorted).
  for (const ConsumerPair &pair : SubConsumers) {
    if (pair.first.empty())
      continue;

    Optional<unsigned> bufferID = SM.getIDForBufferIdentifier(pair.first);
    assert(bufferID.hasValue() && "consumer registered for unknown file");
    CharSourceRange range = SM.getRangeForBuffer(bufferID.getValue());
    ConsumersOrderedByRange.emplace_back(
        ConsumerSpecificInformation(range, pair.second.get()));
  }

  // Sort the "map" by buffer /end/ location, for use with std::lower_bound
  // later. (Sorting by start location would produce the same sort, since the
  // ranges must not be overlapping, but since we need to check end locations
  // later it's consistent to sort by that here.)
  std::sort(ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(),
            [](const ConsumerSpecificInformation &left,
               const ConsumerSpecificInformation &right) -> bool {
              auto compare = std::less<const char *>();
              return compare(getRawLoc(left.range.getEnd()).getPointer(),
                             getRawLoc(right.range.getEnd()).getPointer());
            });

  // Check that the ranges are non-overlapping. If the files really are all
  // distinct, this should be trivially true, but if it's ever not we might end
  // up mis-filing diagnostics.
  assert(ConsumersOrderedByRange.end() ==
             std::adjacent_find(ConsumersOrderedByRange.begin(),
                                ConsumersOrderedByRange.end(),
                                [](const ConsumerSpecificInformation &left,
                                   const ConsumerSpecificInformation &right) {
                                  return left.range.overlaps(right.range);
                                }) &&
         "overlapping ranges despite having distinct files");
}

Optional<FileSpecificDiagnosticConsumer::ConsumerSpecificInformation *>
FileSpecificDiagnosticConsumer::consumerSpecificInformationForLocation(
    SourceManager &SM, SourceLoc loc) const {
  // Diagnostics with invalid locations always go to every consumer.
  if (loc.isInvalid())
    return None;

  // This map is generated on first use and cached, to allow the
  // FileSpecificDiagnosticConsumer to be set up before the source files are
  // actually loaded.
  if (ConsumersOrderedByRange.empty()) {

    // It's possible to get here while a bridging header PCH is being
    // attached-to, if there's some sort of AST-reader warning or error, which
    // happens before CompilerInstance::setUpInputs(), at which point _no_
    // source buffers are loaded in yet. In that case we return None, rather
    // than trying to build a nonsensical map (and actually crashing since we
    // can't find buffers for the inputs).
    assert(!SubConsumers.empty());
    if (!SM.getIDForBufferIdentifier(SubConsumers.begin()->first).hasValue()) {
      assert(llvm::none_of(SubConsumers, [&](const ConsumerPair &pair) {
            return SM.getIDForBufferIdentifier(pair.first).hasValue();
          }));
      return None;
    }
    auto *mutableThis = const_cast<FileSpecificDiagnosticConsumer*>(this);
    mutableThis->computeConsumersOrderedByRange(SM);
  }

  // This std::lower_bound call is doing a binary search for the first range
  // that /might/ contain 'loc'. Specifically, since the ranges are sorted
  // by end location, it's looking for the first range where the end location
  // is greater than or equal to 'loc'.
  const ConsumerSpecificInformation *possiblyContainingRangeIter =
      std::lower_bound(
          ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(), loc,
          [](const ConsumerSpecificInformation &entry, SourceLoc loc) -> bool {
            auto compare = std::less<const char *>();
            return compare(getRawLoc(entry.range.getEnd()).getPointer(),
                           getRawLoc(loc).getPointer());
          });

  if (possiblyContainingRangeIter != ConsumersOrderedByRange.end() &&
      possiblyContainingRangeIter->range.contains(loc)) {
    return const_cast<ConsumerSpecificInformation *>(
        possiblyContainingRangeIter);
  }

  return None;
}

void FileSpecificDiagnosticConsumer::handleDiagnostic(
    SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind,
    StringRef FormatString, ArrayRef<DiagnosticArgument> FormatArgs,
    const DiagnosticInfo &Info) {

  HasAnErrorBeenConsumed |= Kind == DiagnosticKind::Error;

  Optional<ConsumerSpecificInformation *> consumerSpecificInfo;
  switch (Kind) {
  case DiagnosticKind::Error:
  case DiagnosticKind::Warning:
  case DiagnosticKind::Remark:
    consumerSpecificInfo = consumerSpecificInformationForLocation(SM, Loc);
    ConsumerSpecificInfoForSubsequentNotes = consumerSpecificInfo;
    break;
  case DiagnosticKind::Note:
    consumerSpecificInfo = ConsumerSpecificInfoForSubsequentNotes;
    break;
  }
  if (!consumerSpecificInfo.hasValue()) {
    for (auto &subConsumer : SubConsumers) {
      if (subConsumer.second) {
        subConsumer.second->handleDiagnostic(SM, Loc, Kind, FormatString,
                                             FormatArgs, Info);
      }
    }
    return;
  }
  if (!consumerSpecificInfo.getValue()->consumer)
    return; // Suppress non-primary diagnostic in batch mode.

  consumerSpecificInfo.getValue()->consumer->handleDiagnostic(
      SM, Loc, Kind, FormatString, FormatArgs, Info);
  consumerSpecificInfo.getValue()->hasAnErrorBeenEmitted |=
      Kind == DiagnosticKind::Error;
}

bool FileSpecificDiagnosticConsumer::finishProcessing(SourceManager &SM) {
  addNonSpecificErrors(SM);

  // Deliberately don't use std::any_of here because we don't want early-exit
  // behavior.

  bool hadError = false;
  for (auto &subConsumer : SubConsumers)
    hadError |= subConsumer.second && subConsumer.second->finishProcessing(SM);
  return hadError;
}

static void produceNonSpecificError(
    FileSpecificDiagnosticConsumer::ConsumerSpecificInformation &consumerInfo,
    SourceManager &SM) {
  Diagnostic diagnostic(
      diag::error_compilation_stopped_by_errors_in_other_files);

  // Stolen from DiagnosticEngine::emitDiagnostic
  DiagnosticInfo Info;
  Info.ID = diagnostic.getID();

  consumerInfo.consumer->handleDiagnostic(
      SM, consumerInfo.range.getStart(), DiagnosticKind::Error,
      DiagnosticEngine::diagnosticStringFor(diagnostic.getID()), {}, Info);
}

void FileSpecificDiagnosticConsumer::addNonSpecificErrors(SourceManager &SM) {
  if (!HasAnErrorBeenConsumed)
    return;
  for (auto &info : ConsumersOrderedByRange) {
    if (!info.hasAnErrorBeenEmitted && info.consumer) {
      produceNonSpecificError(info, SM);
      info.hasAnErrorBeenEmitted = true;
    }
  }
}

void NullDiagnosticConsumer::handleDiagnostic(
    SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind,
    StringRef FormatString, ArrayRef<DiagnosticArgument> FormatArgs,
    const DiagnosticInfo &Info) {
  DEBUG({
    llvm::dbgs() << "NullDiagnosticConsumer received diagnostic: ";
    DiagnosticEngine::formatDiagnosticText(llvm::dbgs(), FormatString,
                                           FormatArgs);
    llvm::dbgs() << "\n";
  });
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// Name:      vcsentry.cpp
// Purpose:   Implementation of wxExVCSEntry class
// Author:    Anton van Wezenbeek
// Created:   2010-08-27
// RCS-ID:    $Id$
// Copyright: (c) 2010 Anton van Wezenbeek
////////////////////////////////////////////////////////////////////////////////

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/extension/vcsentry.h>
#include <wx/extension/defs.h>
#include <wx/extension/util.h>
#include <wx/extension/vcs.h>

int wxExVCSCommand::m_Instances = 0;

wxExVCSCommand::wxExVCSCommand()
  : m_Command()
  , m_SubMenu()
  , m_SubMenuIsCommand(false)
  , m_No(0)
  , m_Type(VCS_COMMAND_IS_UNKNOWN)
{
}

wxExVCSCommand::wxExVCSCommand(
  const wxString& command,
  const wxString& type,
  const wxString& submenu,
  const wxString& subcommand)
  : m_Command(command)
  , m_SubMenu(!submenu.empty() ? submenu: subcommand)
  , m_SubMenuIsCommand(!subcommand.empty())
  , m_No(m_Instances++)
  , m_Type(From(type))
{
}

int wxExVCSCommand::From(const wxString& type) const
{
  if (type.IsEmpty())
  {
    return VCS_COMMAND_IS_BOTH;
  }
  else if (type == "popup")
  {
    return VCS_COMMAND_IS_POPUP;
  }
  else if (type == "main")
  {
    return VCS_COMMAND_IS_MAIN;
  }
  else
  {
    return VCS_COMMAND_IS_UNKNOWN;
  }
}

const wxString wxExVCSCommand::GetCommand(
  bool include_subcommand,
  bool include_accelerators) const
{
  wxString command = m_Command;

  if (m_SubMenuIsCommand && include_subcommand)
  {
    command += " " + m_SubMenu;
  }

  if (command.Contains("&") && !include_accelerators)
  {
    command.Replace("&", wxEmptyString);
  }

  return command;
}

bool wxExVCSCommand::IsAdd() const
{
  return
    GetCommand(false) == "add";
}

bool wxExVCSCommand::IsCheckout() const
{
  return
    GetCommand(false) == "checkout" ||
    GetCommand(false) == "co";
}

bool wxExVCSCommand::IsCommit() const
{
  return
    GetCommand(false) == "commit" ||
    GetCommand(false) == "ci";
}

bool wxExVCSCommand::IsDiff() const
{
  return
    GetCommand(false) == "diff";
}

bool wxExVCSCommand::IsHelp() const
{
  return
    GetCommand(false) == "help";
}

bool wxExVCSCommand::IsOpen() const
{
  return
    GetCommand(false) == "blame" ||
    GetCommand(false) == "cat" ||
    GetCommand(false) == "diff";
}

bool wxExVCSCommand::IsUpdate() const
{
  return
    GetCommand(false) == "update" ||
    GetCommand(false) == "up";
}

int wxExVCSEntry::m_Instances = wxExVCS::VCS_AUTO + 1;

wxExVCSEntry::wxExVCSEntry()
  : m_No(-1)
  , m_Name()
  , m_SupportKeywordExpansion(false)
{
}

wxExVCSEntry::wxExVCSEntry(const wxXmlNode* node)
  : m_No(m_Instances++)
  , m_Name(node->GetAttribute("name"))
  , m_SupportKeywordExpansion(
      node->GetAttribute("keyword-expansion") == "true")
{
  if (m_Name.empty())
  {
    wxLogError(_("Missing vcs on line: %d"), node->GetLineNumber());
  }
  else
  {
    wxXmlNode *child = node->GetChildren();

    while (child)
    {
      if (child->GetName() == "commands")
      {
        m_Commands = ParseNodeCommands(child);
      }
      else if (child->GetName() == "comment")
      {
        // Ignore comments.
      }
      else
      {
        wxLogError(_("Undefined tag: %s on line: %d"),
          child->GetName().c_str(),
          child->GetLineNumber());
      }

      child = child->GetNext();
    }
  }
}

#if wxUSE_GUI
void wxExVCSEntry::BuildMenu(int base_id, wxMenu* menu, bool is_popup) const
{
  wxMenu* submenu = NULL;

  wxString prev_menu = "XXXXX";

  for (
    auto it = m_Commands.begin();
    it != m_Commands.end();
    ++it)
  {
    bool add = false;

    if (!it->SubMenu().empty() && prev_menu != it->SubMenu())
    {
      if (submenu == NULL)
      {
        submenu = new wxMenu();
        prev_menu = it->SubMenu();
        menu->AppendSubMenu(submenu, it->SubMenu());
      }
    }
    else if (submenu != NULL)
    {
      submenu = NULL;
    }

    switch (it->GetType())
    {
      case wxExVCSCommand::VCS_COMMAND_IS_BOTH: add = true; break;
      case wxExVCSCommand::VCS_COMMAND_IS_POPUP: add = is_popup; break;
      case wxExVCSCommand::VCS_COMMAND_IS_MAIN: add = !is_popup; break;
      case wxExVCSCommand::VCS_COMMAND_IS_UNKNOWN: add = false; break;
      default: wxFAIL;
    }

    if (add)
    {
      wxMenu* usemenu = (submenu == NULL ? menu: submenu);
      usemenu->Append(base_id + it->GetNo(), wxExEllipsed(it->GetCommand()));
    }
  }
}

#endif

const wxExVCSCommand wxExVCSEntry::GetCommand(int command_id) const
{
  if (command_id >= m_Commands.size() || command_id < 0)
  {
    return wxExVCSCommand();
  }
  else
  {
    return m_Commands.at(command_id);
  }
}

const std::vector<wxExVCSCommand> wxExVCSEntry::ParseNodeCommands(
  const wxXmlNode* node) const
{
  std::vector<wxExVCSCommand> v;

  wxExVCSCommand::ResetInstances();

  wxXmlNode* child = node->GetChildren();

  while (child)
  {
    if (child->GetName() == "command")
    {
      if (v.size() == VCS_MAX_COMMANDS)
      {
        wxLogError(_("Reached commands limit: %d"), VCS_MAX_COMMANDS);
      }
      else
      {
        const wxString content = child->GetNodeContent().Strip(wxString::both);
        const wxString attrib = child->GetAttribute("type");
        const wxString submenu = child->GetAttribute("submenu");
        const wxString subcommand = child->GetAttribute("subcommand");
        v.push_back(wxExVCSCommand(content, attrib, submenu, subcommand));
      }
    }
    else if (child->GetName() == "comment")
    {
      // Ignore comments.
    }
    else
    {
      wxLogError(_("Undefined tag: %s on line: %d"),
        child->GetName().c_str(),
        child->GetLineNumber());
    }

    child = child->GetNext();
  }

  return v;
}
<commit_msg>fixed accel in menu<commit_after>////////////////////////////////////////////////////////////////////////////////
// Name:      vcsentry.cpp
// Purpose:   Implementation of wxExVCSEntry class
// Author:    Anton van Wezenbeek
// Created:   2010-08-27
// RCS-ID:    $Id$
// Copyright: (c) 2010 Anton van Wezenbeek
////////////////////////////////////////////////////////////////////////////////

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/extension/vcsentry.h>
#include <wx/extension/defs.h>
#include <wx/extension/util.h>
#include <wx/extension/vcs.h>

int wxExVCSCommand::m_Instances = 0;

wxExVCSCommand::wxExVCSCommand()
  : m_Command()
  , m_SubMenu()
  , m_SubMenuIsCommand(false)
  , m_No(0)
  , m_Type(VCS_COMMAND_IS_UNKNOWN)
{
}

wxExVCSCommand::wxExVCSCommand(
  const wxString& command,
  const wxString& type,
  const wxString& submenu,
  const wxString& subcommand)
  : m_Command(command)
  , m_SubMenu(!submenu.empty() ? submenu: subcommand)
  , m_SubMenuIsCommand(!subcommand.empty())
  , m_No(m_Instances++)
  , m_Type(From(type))
{
}

int wxExVCSCommand::From(const wxString& type) const
{
  if (type.IsEmpty())
  {
    return VCS_COMMAND_IS_BOTH;
  }
  else if (type == "popup")
  {
    return VCS_COMMAND_IS_POPUP;
  }
  else if (type == "main")
  {
    return VCS_COMMAND_IS_MAIN;
  }
  else
  {
    return VCS_COMMAND_IS_UNKNOWN;
  }
}

const wxString wxExVCSCommand::GetCommand(
  bool include_subcommand,
  bool include_accelerators) const
{
  wxString command = m_Command;

  if (m_SubMenuIsCommand && include_subcommand)
  {
    command += " " + m_SubMenu;
  }

  if (command.Contains("&") && !include_accelerators)
  {
    command.Replace("&", wxEmptyString);
  }

  return command;
}

bool wxExVCSCommand::IsAdd() const
{
  return
    GetCommand(false) == "add";
}

bool wxExVCSCommand::IsCheckout() const
{
  return
    GetCommand(false) == "checkout" ||
    GetCommand(false) == "co";
}

bool wxExVCSCommand::IsCommit() const
{
  return
    GetCommand(false) == "commit" ||
    GetCommand(false) == "ci";
}

bool wxExVCSCommand::IsDiff() const
{
  return
    GetCommand(false) == "diff";
}

bool wxExVCSCommand::IsHelp() const
{
  return
    GetCommand(false) == "help";
}

bool wxExVCSCommand::IsOpen() const
{
  return
    GetCommand(false) == "blame" ||
    GetCommand(false) == "cat" ||
    GetCommand(false) == "diff";
}

bool wxExVCSCommand::IsUpdate() const
{
  return
    GetCommand(false) == "update" ||
    GetCommand(false) == "up";
}

int wxExVCSEntry::m_Instances = wxExVCS::VCS_AUTO + 1;

wxExVCSEntry::wxExVCSEntry()
  : m_No(-1)
  , m_Name()
  , m_SupportKeywordExpansion(false)
{
}

wxExVCSEntry::wxExVCSEntry(const wxXmlNode* node)
  : m_No(m_Instances++)
  , m_Name(node->GetAttribute("name"))
  , m_SupportKeywordExpansion(
      node->GetAttribute("keyword-expansion") == "true")
{
  if (m_Name.empty())
  {
    wxLogError(_("Missing vcs on line: %d"), node->GetLineNumber());
  }
  else
  {
    wxXmlNode *child = node->GetChildren();

    while (child)
    {
      if (child->GetName() == "commands")
      {
        m_Commands = ParseNodeCommands(child);
      }
      else if (child->GetName() == "comment")
      {
        // Ignore comments.
      }
      else
      {
        wxLogError(_("Undefined tag: %s on line: %d"),
          child->GetName().c_str(),
          child->GetLineNumber());
      }

      child = child->GetNext();
    }
  }
}

#if wxUSE_GUI
void wxExVCSEntry::BuildMenu(int base_id, wxMenu* menu, bool is_popup) const
{
  wxMenu* submenu = NULL;

  wxString prev_menu = "XXXXX";

  for (
    auto it = m_Commands.begin();
    it != m_Commands.end();
    ++it)
  {
    bool add = false;

    if (!it->SubMenu().empty() && prev_menu != it->SubMenu())
    {
      if (submenu == NULL)
      {
        submenu = new wxMenu();
        prev_menu = it->SubMenu();
        menu->AppendSubMenu(submenu, it->SubMenu());
      }
    }
    else if (submenu != NULL)
    {
      submenu = NULL;
    }

    switch (it->GetType())
    {
      case wxExVCSCommand::VCS_COMMAND_IS_BOTH: add = true; break;
      case wxExVCSCommand::VCS_COMMAND_IS_POPUP: add = is_popup; break;
      case wxExVCSCommand::VCS_COMMAND_IS_MAIN: add = !is_popup; break;
      case wxExVCSCommand::VCS_COMMAND_IS_UNKNOWN: add = false; break;
      default: wxFAIL;
    }

    if (add)
    {
      wxMenu* usemenu = (submenu == NULL ? menu: submenu);
      usemenu->Append(
        base_id + it->GetNo(),
        wxExEllipsed(it->GetCommand(false, true))); // use no sub and do accel
    }
  }
}

#endif

const wxExVCSCommand wxExVCSEntry::GetCommand(int command_id) const
{
  if (command_id >= m_Commands.size() || command_id < 0)
  {
    return wxExVCSCommand();
  }
  else
  {
    return m_Commands.at(command_id);
  }
}

const std::vector<wxExVCSCommand> wxExVCSEntry::ParseNodeCommands(
  const wxXmlNode* node) const
{
  std::vector<wxExVCSCommand> v;

  wxExVCSCommand::ResetInstances();

  wxXmlNode* child = node->GetChildren();

  while (child)
  {
    if (child->GetName() == "command")
    {
      if (v.size() == VCS_MAX_COMMANDS)
      {
        wxLogError(_("Reached commands limit: %d"), VCS_MAX_COMMANDS);
      }
      else
      {
        const wxString content = child->GetNodeContent().Strip(wxString::both);
        const wxString attrib = child->GetAttribute("type");
        const wxString submenu = child->GetAttribute("submenu");
        const wxString subcommand = child->GetAttribute("subcommand");
        v.push_back(wxExVCSCommand(content, attrib, submenu, subcommand));
      }
    }
    else if (child->GetName() == "comment")
    {
      // Ignore comments.
    }
    else
    {
      wxLogError(_("Undefined tag: %s on line: %d"),
        child->GetName().c_str(),
        child->GetLineNumber());
    }

    child = child->GetNext();
  }

  return v;
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013-2014 winlin

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <srs_app_server.hpp>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <algorithm>

#include <srs_kernel_log.hpp>
#include <srs_kernel_error.hpp>
#include <srs_app_rtmp_conn.hpp>
#include <srs_app_config.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_app_http_api.hpp>
#include <srs_app_http_conn.hpp>

#define SERVER_LISTEN_BACKLOG 512
#define SRS_TIME_RESOLUTION_MS 500

SrsListener::SrsListener(SrsServer* _server, SrsListenerType _type)
{
    fd = -1;
    stfd = NULL;

    port = 0;
    server = _server;
    type = _type;

    pthread = new SrsThread(this, 0);
}

SrsListener::~SrsListener()
{
    srs_close_stfd(stfd);

    pthread->stop();
    srs_freep(pthread);

    // st does not close it sometimes,
    // close it manually.
    close(fd);
}

int SrsListener::listen(int _port)
{
    int ret = ERROR_SUCCESS;

    port = _port;

    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        ret = ERROR_SOCKET_CREATE;
        srs_error("create linux socket error. ret=%d", ret);
        return ret;
    }
    srs_verbose("create linux socket success. fd=%d", fd);

    int reuse_socket = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) {
        ret = ERROR_SOCKET_SETREUSE;
        srs_error("setsockopt reuse-addr error. ret=%d", ret);
        return ret;
    }
    srs_verbose("setsockopt reuse-addr success. fd=%d", fd);

    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;
    if (bind(fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
        ret = ERROR_SOCKET_BIND;
        srs_error("bind socket error. ret=%d", ret);
        return ret;
    }
    srs_verbose("bind socket success. fd=%d", fd);

    if (::listen(fd, SERVER_LISTEN_BACKLOG) == -1) {
        ret = ERROR_SOCKET_LISTEN;
        srs_error("listen socket error. ret=%d", ret);
        return ret;
    }
    srs_verbose("listen socket success. fd=%d", fd);

    if ((stfd = st_netfd_open_socket(fd)) == NULL){
        ret = ERROR_ST_OPEN_SOCKET;
        srs_error("st_netfd_open_socket open socket failed. ret=%d", ret);
        return ret;
    }
    srs_verbose("st open socket success. fd=%d", fd);

    if ((ret = pthread->start()) != ERROR_SUCCESS) {
        srs_error("st_thread_create listen thread error. ret=%d", ret);
        return ret;
    }
    srs_verbose("create st listen thread success.");

    srs_trace("server started, listen at port=%d, type=%d, fd=%d", port, type, fd);

    return ret;
}

void SrsListener::on_enter_loop()
{
    srs_trace("listen cycle start, port=%d, type=%d, fd=%d", port, type, fd);
}

int SrsListener::cycle()
{
    int ret = ERROR_SUCCESS;

    st_netfd_t client_stfd = st_accept(stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT);

    if(client_stfd == NULL){
        // ignore error.
        srs_warn("ignore accept thread stoppped for accept client error");
        return ret;
    }
    srs_verbose("get a client. fd=%d", st_netfd_fileno(client_stfd));

    if ((ret = server->accept_client(type, client_stfd)) != ERROR_SUCCESS) {
        srs_warn("accept client error. ret=%d", ret);
        return ret;
    }

    srs_verbose("accept client finished. conns=%d, ret=%d", (int)conns.size(), ret);

    return ret;
}

SrsServer::SrsServer()
{
    signal_reload = false;
    signal_gmc_stop = false;

    srs_assert(_srs_config);
    _srs_config->subscribe(this);
}

SrsServer::~SrsServer()
{
    _srs_config->unsubscribe(this);

    if (true) {
        std::vector<SrsConnection*>::iterator it;
        for (it = conns.begin(); it != conns.end(); ++it) {
            SrsConnection* conn = *it;
            srs_freep(conn);
        }
        conns.clear();
    }

    close_listeners();
}

int SrsServer::initialize()
{
    int ret = ERROR_SUCCESS;
    return ret;
}

int SrsServer::acquire_pid_file()
{
    int ret = ERROR_SUCCESS;

    std::string pid_file = _srs_config->get_pid_file();

    // -rw-r--r--
    // 644
    int mode = S_IRUSR | S_IWUSR |  S_IRGRP | S_IROTH;

    int fd;
    // open pid file
    if ((fd = ::open(pid_file.c_str(), O_WRONLY | O_CREAT, mode)) < 0) {
        ret = ERROR_SYSTEM_PID_ACQUIRE;
        srs_error("open pid file %s error, ret=%#x", pid_file.c_str(), ret);
        return ret;
    }

    // require write lock
    flock lock;

    lock.l_type = F_WRLCK; // F_RDLCK, F_WRLCK, F_UNLCK
    lock.l_start = 0; // type offset, relative to l_whence
    lock.l_whence = SEEK_SET;  // SEEK_SET, SEEK_CUR, SEEK_END
    lock.l_len = 0;

    if (fcntl(fd, F_SETLK, &lock) < 0) {
        if(errno == EACCES || errno == EAGAIN) {
            ret = ERROR_SYSTEM_PID_ALREADY_RUNNING;
            srs_error("srs is already running! ret=%#x", ret);
            return ret;
        }

        ret = ERROR_SYSTEM_PID_LOCK;
        srs_error("require lock for file %s error! ret=%#x", pid_file.c_str(), ret);
        return ret;
    }

    // truncate file
    if (ftruncate(fd, 0) < 0) {
        ret = ERROR_SYSTEM_PID_TRUNCATE_FILE;
        srs_error("truncate pid file %s error! ret=%#x", pid_file.c_str(), ret);
        return ret;
    }

    int pid = (int)getpid();

    // write the pid
    char buf[512];
    snprintf(buf, sizeof(buf), "%d", pid);
    if (write(fd, buf, strlen(buf)) != (int)strlen(buf)) {
        ret = ERROR_SYSTEM_PID_WRITE_FILE;
        srs_error("write our pid error! pid=%d file=%s ret=%#x", pid, pid_file.c_str(), ret);
        return ret;
    }

    // auto close when fork child process.
    int val;
    if ((val = fcntl(fd, F_GETFD, 0)) < 0) {
        ret = ERROR_SYSTEM_PID_GET_FILE_INFO;
        srs_error("fnctl F_GETFD error! file=%s ret=%#x", pid_file.c_str(), ret);
        return ret;
    }
    val |= FD_CLOEXEC;
    if (fcntl(fd, F_SETFD, val) < 0) {
        ret = ERROR_SYSTEM_PID_SET_FILE_INFO;
        srs_error("fcntl F_SETFD error! file=%s ret=%#x", pid_file.c_str(), ret);
        return ret;
    }

    srs_trace("write pid=%d to %s success!", pid, pid_file.c_str());

    return ret;
}

int SrsServer::initialize_st()
{
    int ret = ERROR_SUCCESS;

    // use linux epoll.
    if (st_set_eventsys(ST_EVENTSYS_ALT) == -1) {
        ret = ERROR_ST_SET_EPOLL;
        srs_error("st_set_eventsys use linux epoll failed. ret=%d", ret);
        return ret;
    }
    srs_verbose("st_set_eventsys use linux epoll success");

    if(st_init() != 0){
        ret = ERROR_ST_INITIALIZE;
        srs_error("st_init failed. ret=%d", ret);
        return ret;
    }
    srs_verbose("st_init success");

    // set current log id.
    _srs_context->generate_id();
    srs_info("log set id success");

    return ret;
}

int SrsServer::listen()
{
    int ret = ERROR_SUCCESS;

    SrsConfDirective* conf = NULL;

    // stream service port.
    conf = _srs_config->get_listen();
    srs_assert(conf);

    close_listeners();

    for (int i = 0; i < (int)conf->args.size(); i++) {
        SrsListener* listener = new SrsListener(this, SrsListenerRtmpStream);
        listeners.push_back(listener);

        int port = ::atoi(conf->args.at(i).c_str());
        if ((ret = listener->listen(port)) != ERROR_SUCCESS) {
            srs_error("RTMP stream listen at port %d failed. ret=%d", port, ret);
            return ret;
        }
    }

    if (_srs_config->get_http_api_enabled()) {
        SrsListener* listener = new SrsListener(this, SrsListenerHttpApi);
        listeners.push_back(listener);

        int port = _srs_config->get_http_api_listen();
        if ((ret = listener->listen(port)) != ERROR_SUCCESS) {
            srs_error("HTTP api listen at port %d failed. ret=%d", port, ret);
            return ret;
        }
    }

    if (_srs_config->get_http_stream_enabled()) {
        SrsListener* listener = new SrsListener(this, SrsListenerHttpStream);
        listeners.push_back(listener);

        int port = _srs_config->get_http_stream_listen();
        if ((ret = listener->listen(port)) != ERROR_SUCCESS) {
            srs_error("HTTP stream listen at port %d failed. ret=%d", port, ret);
            return ret;
        }
    }

    return ret;
}

int SrsServer::cycle()
{
    int ret = ERROR_SUCCESS;

    // the deamon thread, update the time cache
    while (true) {
        st_usleep(SRS_TIME_RESOLUTION_MS * 1000);
        srs_update_system_time_ms();

// for gperf heap checker,
// @see: research/gperftools/heap-checker/heap_checker.cc
// if user interrupt the program, exit to check mem leak.
// but, if gperf, use reload to ensure main return normally,
// because directly exit will cause core-dump.
#ifdef SRS_GPERF_MC
        if (signal_gmc_stop) {
            break;
        }
#endif

        if (signal_reload) {
            signal_reload = false;
            srs_info("get signal reload, to reload the config.");

            if ((ret = _srs_config->reload()) != ERROR_SUCCESS) {
                srs_error("reload config failed. ret=%d", ret);
                return ret;
            }
            srs_trace("reload config success.");
        }
    }

    return ret;
}

void SrsServer::remove(SrsConnection* conn)
{
    std::vector<SrsConnection*>::iterator it = std::find(conns.begin(), conns.end(), conn);

    if (it != conns.end()) {
        conns.erase(it);
    }

    srs_info("conn removed. conns=%d", (int)conns.size());

    // all connections are created by server,
    // so we free it here.
    srs_freep(conn);
}

void SrsServer::on_signal(int signo)
{
    if (signo == SIGNAL_RELOAD) {
        signal_reload = true;
        return;
    }

    if (signo == SIGINT) {
#ifdef SRS_GPERF_MC
        srs_trace("gmc is on, main cycle will terminate normally.");
        signal_gmc_stop = true;
#else
        srs_trace("user terminate program");
        exit(0);
#endif
        return;
    }

    if (signo == SIGTERM) {
        srs_trace("user terminate program");
        exit(0);
        return;
    }
}

void SrsServer::close_listeners()
{
    std::vector<SrsListener*>::iterator it;
    for (it = listeners.begin(); it != listeners.end(); ++it) {
        SrsListener* listener = *it;
        srs_freep(listener);
    }
    listeners.clear();
}

int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd)
{
    int ret = ERROR_SUCCESS;

    int max_connections = _srs_config->get_max_connections();
    if ((int)conns.size() >= max_connections) {
        int fd = st_netfd_fileno(client_stfd);

        srs_error("exceed the max connections, drop client: "
            "clients=%d, max=%d, fd=%d", (int)conns.size(), max_connections, fd);

        srs_close_stfd(client_stfd);

        return ret;
    }

    SrsConnection* conn = NULL;
    if (type == SrsListenerRtmpStream) {
        conn = new SrsRtmpConn(this, client_stfd);
    } else if (type == SrsListenerHttpApi) {
#ifdef SRS_HTTP_API
        conn = new SrsHttpApi(this, client_stfd);
#else
        srs_warn("close http client for server not support http-api");
        srs_close_stfd(client_stfd);
        return ret;
#endif
    } else if (type == SrsListenerHttpStream) {
#ifdef SRS_HTTP_SERVER
        conn = new SrsHttpConn(this, client_stfd);
#else
        srs_warn("close http client for server not support http-server");
        srs_close_stfd(client_stfd);
        return ret;
#endif
    } else {
        // TODO: FIXME: handler others
    }
    srs_assert(conn);

    // directly enqueue, the cycle thread will remove the client.
    conns.push_back(conn);
    srs_verbose("add conn from port %d to vector. conns=%d", port, (int)conns.size());

    // cycle will start process thread and when finished remove the client.
    if ((ret = conn->start()) != ERROR_SUCCESS) {
        return ret;
    }
    srs_verbose("conn start finished. ret=%d", ret);

    return ret;
}

int SrsServer::on_reload_listen()
{
    return listen();
}
<commit_msg>refine code, donot listen if not enabled http<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013-2014 winlin

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <srs_app_server.hpp>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <algorithm>

#include <srs_kernel_log.hpp>
#include <srs_kernel_error.hpp>
#include <srs_app_rtmp_conn.hpp>
#include <srs_app_config.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_app_http_api.hpp>
#include <srs_app_http_conn.hpp>

#define SERVER_LISTEN_BACKLOG 512
#define SRS_TIME_RESOLUTION_MS 500

SrsListener::SrsListener(SrsServer* _server, SrsListenerType _type)
{
    fd = -1;
    stfd = NULL;

    port = 0;
    server = _server;
    type = _type;

    pthread = new SrsThread(this, 0);
}

SrsListener::~SrsListener()
{
    srs_close_stfd(stfd);

    pthread->stop();
    srs_freep(pthread);

    // st does not close it sometimes,
    // close it manually.
    close(fd);
}

int SrsListener::listen(int _port)
{
    int ret = ERROR_SUCCESS;

    port = _port;

    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        ret = ERROR_SOCKET_CREATE;
        srs_error("create linux socket error. ret=%d", ret);
        return ret;
    }
    srs_verbose("create linux socket success. fd=%d", fd);

    int reuse_socket = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) {
        ret = ERROR_SOCKET_SETREUSE;
        srs_error("setsockopt reuse-addr error. ret=%d", ret);
        return ret;
    }
    srs_verbose("setsockopt reuse-addr success. fd=%d", fd);

    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;
    if (bind(fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
        ret = ERROR_SOCKET_BIND;
        srs_error("bind socket error. ret=%d", ret);
        return ret;
    }
    srs_verbose("bind socket success. fd=%d", fd);

    if (::listen(fd, SERVER_LISTEN_BACKLOG) == -1) {
        ret = ERROR_SOCKET_LISTEN;
        srs_error("listen socket error. ret=%d", ret);
        return ret;
    }
    srs_verbose("listen socket success. fd=%d", fd);

    if ((stfd = st_netfd_open_socket(fd)) == NULL){
        ret = ERROR_ST_OPEN_SOCKET;
        srs_error("st_netfd_open_socket open socket failed. ret=%d", ret);
        return ret;
    }
    srs_verbose("st open socket success. fd=%d", fd);

    if ((ret = pthread->start()) != ERROR_SUCCESS) {
        srs_error("st_thread_create listen thread error. ret=%d", ret);
        return ret;
    }
    srs_verbose("create st listen thread success.");

    srs_trace("server started, listen at port=%d, type=%d, fd=%d", port, type, fd);

    return ret;
}

void SrsListener::on_enter_loop()
{
    srs_trace("listen cycle start, port=%d, type=%d, fd=%d", port, type, fd);
}

int SrsListener::cycle()
{
    int ret = ERROR_SUCCESS;

    st_netfd_t client_stfd = st_accept(stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT);

    if(client_stfd == NULL){
        // ignore error.
        srs_warn("ignore accept thread stoppped for accept client error");
        return ret;
    }
    srs_verbose("get a client. fd=%d", st_netfd_fileno(client_stfd));

    if ((ret = server->accept_client(type, client_stfd)) != ERROR_SUCCESS) {
        srs_warn("accept client error. ret=%d", ret);
        return ret;
    }

    srs_verbose("accept client finished. conns=%d, ret=%d", (int)conns.size(), ret);

    return ret;
}

SrsServer::SrsServer()
{
    signal_reload = false;
    signal_gmc_stop = false;

    srs_assert(_srs_config);
    _srs_config->subscribe(this);
}

SrsServer::~SrsServer()
{
    _srs_config->unsubscribe(this);

    if (true) {
        std::vector<SrsConnection*>::iterator it;
        for (it = conns.begin(); it != conns.end(); ++it) {
            SrsConnection* conn = *it;
            srs_freep(conn);
        }
        conns.clear();
    }

    close_listeners();
}

int SrsServer::initialize()
{
    int ret = ERROR_SUCCESS;
    return ret;
}

int SrsServer::acquire_pid_file()
{
    int ret = ERROR_SUCCESS;

    std::string pid_file = _srs_config->get_pid_file();

    // -rw-r--r--
    // 644
    int mode = S_IRUSR | S_IWUSR |  S_IRGRP | S_IROTH;

    int fd;
    // open pid file
    if ((fd = ::open(pid_file.c_str(), O_WRONLY | O_CREAT, mode)) < 0) {
        ret = ERROR_SYSTEM_PID_ACQUIRE;
        srs_error("open pid file %s error, ret=%#x", pid_file.c_str(), ret);
        return ret;
    }

    // require write lock
    flock lock;

    lock.l_type = F_WRLCK; // F_RDLCK, F_WRLCK, F_UNLCK
    lock.l_start = 0; // type offset, relative to l_whence
    lock.l_whence = SEEK_SET;  // SEEK_SET, SEEK_CUR, SEEK_END
    lock.l_len = 0;

    if (fcntl(fd, F_SETLK, &lock) < 0) {
        if(errno == EACCES || errno == EAGAIN) {
            ret = ERROR_SYSTEM_PID_ALREADY_RUNNING;
            srs_error("srs is already running! ret=%#x", ret);
            return ret;
        }

        ret = ERROR_SYSTEM_PID_LOCK;
        srs_error("require lock for file %s error! ret=%#x", pid_file.c_str(), ret);
        return ret;
    }

    // truncate file
    if (ftruncate(fd, 0) < 0) {
        ret = ERROR_SYSTEM_PID_TRUNCATE_FILE;
        srs_error("truncate pid file %s error! ret=%#x", pid_file.c_str(), ret);
        return ret;
    }

    int pid = (int)getpid();

    // write the pid
    char buf[512];
    snprintf(buf, sizeof(buf), "%d", pid);
    if (write(fd, buf, strlen(buf)) != (int)strlen(buf)) {
        ret = ERROR_SYSTEM_PID_WRITE_FILE;
        srs_error("write our pid error! pid=%d file=%s ret=%#x", pid, pid_file.c_str(), ret);
        return ret;
    }

    // auto close when fork child process.
    int val;
    if ((val = fcntl(fd, F_GETFD, 0)) < 0) {
        ret = ERROR_SYSTEM_PID_GET_FILE_INFO;
        srs_error("fnctl F_GETFD error! file=%s ret=%#x", pid_file.c_str(), ret);
        return ret;
    }
    val |= FD_CLOEXEC;
    if (fcntl(fd, F_SETFD, val) < 0) {
        ret = ERROR_SYSTEM_PID_SET_FILE_INFO;
        srs_error("fcntl F_SETFD error! file=%s ret=%#x", pid_file.c_str(), ret);
        return ret;
    }

    srs_trace("write pid=%d to %s success!", pid, pid_file.c_str());

    return ret;
}

int SrsServer::initialize_st()
{
    int ret = ERROR_SUCCESS;

    // use linux epoll.
    if (st_set_eventsys(ST_EVENTSYS_ALT) == -1) {
        ret = ERROR_ST_SET_EPOLL;
        srs_error("st_set_eventsys use linux epoll failed. ret=%d", ret);
        return ret;
    }
    srs_verbose("st_set_eventsys use linux epoll success");

    if(st_init() != 0){
        ret = ERROR_ST_INITIALIZE;
        srs_error("st_init failed. ret=%d", ret);
        return ret;
    }
    srs_verbose("st_init success");

    // set current log id.
    _srs_context->generate_id();
    srs_info("log set id success");

    return ret;
}

int SrsServer::listen()
{
    int ret = ERROR_SUCCESS;

    SrsConfDirective* conf = NULL;

    // stream service port.
    conf = _srs_config->get_listen();
    srs_assert(conf);

    close_listeners();

    for (int i = 0; i < (int)conf->args.size(); i++) {
        SrsListener* listener = new SrsListener(this, SrsListenerRtmpStream);
        listeners.push_back(listener);

        int port = ::atoi(conf->args.at(i).c_str());
        if ((ret = listener->listen(port)) != ERROR_SUCCESS) {
            srs_error("RTMP stream listen at port %d failed. ret=%d", port, ret);
            return ret;
        }
    }

#ifdef SRS_HTTP_API
    if (_srs_config->get_http_api_enabled()) {
        SrsListener* listener = new SrsListener(this, SrsListenerHttpApi);
        listeners.push_back(listener);

        int port = _srs_config->get_http_api_listen();
        if ((ret = listener->listen(port)) != ERROR_SUCCESS) {
            srs_error("HTTP api listen at port %d failed. ret=%d", port, ret);
            return ret;
        }
    }
#endif

#ifdef SRS_HTTP_SERVER
    if (_srs_config->get_http_stream_enabled()) {
        SrsListener* listener = new SrsListener(this, SrsListenerHttpStream);
        listeners.push_back(listener);

        int port = _srs_config->get_http_stream_listen();
        if ((ret = listener->listen(port)) != ERROR_SUCCESS) {
            srs_error("HTTP stream listen at port %d failed. ret=%d", port, ret);
            return ret;
        }
    }
#endif

    return ret;
}

int SrsServer::cycle()
{
    int ret = ERROR_SUCCESS;

    // the deamon thread, update the time cache
    while (true) {
        st_usleep(SRS_TIME_RESOLUTION_MS * 1000);
        srs_update_system_time_ms();

// for gperf heap checker,
// @see: research/gperftools/heap-checker/heap_checker.cc
// if user interrupt the program, exit to check mem leak.
// but, if gperf, use reload to ensure main return normally,
// because directly exit will cause core-dump.
#ifdef SRS_GPERF_MC
        if (signal_gmc_stop) {
            break;
        }
#endif

        if (signal_reload) {
            signal_reload = false;
            srs_info("get signal reload, to reload the config.");

            if ((ret = _srs_config->reload()) != ERROR_SUCCESS) {
                srs_error("reload config failed. ret=%d", ret);
                return ret;
            }
            srs_trace("reload config success.");
        }
    }

    return ret;
}

void SrsServer::remove(SrsConnection* conn)
{
    std::vector<SrsConnection*>::iterator it = std::find(conns.begin(), conns.end(), conn);

    if (it != conns.end()) {
        conns.erase(it);
    }

    srs_info("conn removed. conns=%d", (int)conns.size());

    // all connections are created by server,
    // so we free it here.
    srs_freep(conn);
}

void SrsServer::on_signal(int signo)
{
    if (signo == SIGNAL_RELOAD) {
        signal_reload = true;
        return;
    }

    if (signo == SIGINT) {
#ifdef SRS_GPERF_MC
        srs_trace("gmc is on, main cycle will terminate normally.");
        signal_gmc_stop = true;
#else
        srs_trace("user terminate program");
        exit(0);
#endif
        return;
    }

    if (signo == SIGTERM) {
        srs_trace("user terminate program");
        exit(0);
        return;
    }
}

void SrsServer::close_listeners()
{
    std::vector<SrsListener*>::iterator it;
    for (it = listeners.begin(); it != listeners.end(); ++it) {
        SrsListener* listener = *it;
        srs_freep(listener);
    }
    listeners.clear();
}

int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd)
{
    int ret = ERROR_SUCCESS;

    int max_connections = _srs_config->get_max_connections();
    if ((int)conns.size() >= max_connections) {
        int fd = st_netfd_fileno(client_stfd);

        srs_error("exceed the max connections, drop client: "
            "clients=%d, max=%d, fd=%d", (int)conns.size(), max_connections, fd);

        srs_close_stfd(client_stfd);

        return ret;
    }

    SrsConnection* conn = NULL;
    if (type == SrsListenerRtmpStream) {
        conn = new SrsRtmpConn(this, client_stfd);
    } else if (type == SrsListenerHttpApi) {
#ifdef SRS_HTTP_API
        conn = new SrsHttpApi(this, client_stfd);
#else
        srs_warn("close http client for server not support http-api");
        srs_close_stfd(client_stfd);
        return ret;
#endif
    } else if (type == SrsListenerHttpStream) {
#ifdef SRS_HTTP_SERVER
        conn = new SrsHttpConn(this, client_stfd);
#else
        srs_warn("close http client for server not support http-server");
        srs_close_stfd(client_stfd);
        return ret;
#endif
    } else {
        // TODO: FIXME: handler others
    }
    srs_assert(conn);

    // directly enqueue, the cycle thread will remove the client.
    conns.push_back(conn);
    srs_verbose("add conn from port %d to vector. conns=%d", port, (int)conns.size());

    // cycle will start process thread and when finished remove the client.
    if ((ret = conn->start()) != ERROR_SUCCESS) {
        return ret;
    }
    srs_verbose("conn start finished. ret=%d", ret);

    return ret;
}

int SrsServer::on_reload_listen()
{
    return listen();
}
<|endoftext|>