<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "basevalidatinglineedit.h"

#include <QDebug>

enum { debug = 0 };

/*!
    \namespace Utils
    General utility library namespace
*/

/*! \class Utils::BaseValidatingLineEdit

    \brief Base class for line edits that perform validation.

    Performs validation in a virtual  validate() function to be implemented in
    derived classes.
    When invalid, the text color will turn red and a tooltip will
    contain the error message. This approach is less intrusive than a
    QValidator which will prevent the user from entering certain characters.

    The widget has a concept of an "initialText" which can be something like
    "<Enter name here>". This results in state 'DisplayingInitialText', which
    is not valid, but is not marked red.
*/

namespace Utils {

struct BaseValidatingLineEditPrivate {
    explicit BaseValidatingLineEditPrivate(const QWidget *w);

    const QColor m_okTextColor;
    QColor m_errorTextColor;

    BaseValidatingLineEdit::State m_state;
    QString m_errorMessage;
    QString m_initialText;
    bool m_firstChange;
};

BaseValidatingLineEditPrivate::BaseValidatingLineEditPrivate(const QWidget *w) :
    m_okTextColor(BaseValidatingLineEdit::textColor(w)),
    m_errorTextColor(Qt::red),
    m_state(BaseValidatingLineEdit::Invalid),
    m_firstChange(true)
{
}

BaseValidatingLineEdit::BaseValidatingLineEdit(QWidget *parent) :
    QLineEdit(parent),
    m_bd(new BaseValidatingLineEditPrivate(this))
{
    // Note that textChanged() is also triggered automagically by
    // QLineEdit::setText(), no need to trigger manually.
    connect(this, SIGNAL(textChanged(QString)), this, SLOT(slotChanged(QString)));
}

BaseValidatingLineEdit::~BaseValidatingLineEdit()
{
    delete m_bd;
}

QString BaseValidatingLineEdit::initialText() const
{
    return m_bd->m_initialText;
}

void BaseValidatingLineEdit::setInitialText(const QString &t)
{
    if (m_bd->m_initialText != t) {
        m_bd->m_initialText = t;
        m_bd->m_firstChange = true;
        setText(t);
    }
}

QColor BaseValidatingLineEdit::errorColor() const
{
    return m_bd->m_errorTextColor;
}

void BaseValidatingLineEdit::setErrorColor(const  QColor &c)
{
     m_bd->m_errorTextColor = c;
}

QColor BaseValidatingLineEdit::textColor(const QWidget *w)
{
    return w->palette().color(QPalette::Active, QPalette::Text);
}

void BaseValidatingLineEdit::setTextColor(QWidget *w, const QColor &c)
{
    QPalette palette = w->palette();
    palette.setColor(QPalette::Active, QPalette::Text, c);
    w->setPalette(palette);
}

BaseValidatingLineEdit::State BaseValidatingLineEdit::state() const
{
    return m_bd->m_state;
}

bool BaseValidatingLineEdit::isValid() const
{
    return m_bd->m_state == Valid;
}

QString BaseValidatingLineEdit::errorMessage() const
{
    return m_bd->m_errorMessage;
}

void BaseValidatingLineEdit::slotChanged(const QString &t)
{
    m_bd->m_errorMessage.clear();
    // Are we displaying the initial text?
    const bool isDisplayingInitialText = !m_bd->m_initialText.isEmpty() && t == m_bd->m_initialText;
    const State newState = isDisplayingInitialText ?
                               DisplayingInitialText :
                               (validate(t, &m_bd->m_errorMessage) ? Valid : Invalid);
    setToolTip(m_bd->m_errorMessage);
    if (debug)
        qDebug() << Q_FUNC_INFO << t << "State" <<  m_bd->m_state << "->" << newState << m_bd->m_errorMessage;
    // Changed..figure out if valid changed. DisplayingInitialText is not valid,
    // but should not show error color. Also trigger on the first change.
    if (newState != m_bd->m_state || m_bd->m_firstChange) {
        const bool validHasChanged = (m_bd->m_state == Valid) != (newState == Valid);
        m_bd->m_state = newState;
        m_bd->m_firstChange = false;
        setTextColor(this, newState == Invalid ? m_bd->m_errorTextColor : m_bd->m_okTextColor);
        if (validHasChanged) {
            emit validChanged(newState == Valid);
            emit validChanged();
        }
    }
    bool block = blockSignals(true);
    const QString fixedString = fixInputString(t);
    if (t != fixedString)
        setText(fixedString);
    blockSignals(block);
}

void BaseValidatingLineEdit::slotReturnPressed()
{
    if (isValid())
        emit validReturnPressed();
}

void BaseValidatingLineEdit::triggerChanged()
{
    slotChanged(text());
}

QString BaseValidatingLineEdit::fixInputString(const QString &string)
{
    return string;
}

} // namespace Utils
<commit_msg>BaseValidatingLineEdit:: keeping the cursor pos<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "basevalidatinglineedit.h"

#include <QDebug>

enum { debug = 0 };

/*!
    \namespace Utils
    General utility library namespace
*/

/*! \class Utils::BaseValidatingLineEdit

    \brief Base class for line edits that perform validation.

    Performs validation in a virtual  validate() function to be implemented in
    derived classes.
    When invalid, the text color will turn red and a tooltip will
    contain the error message. This approach is less intrusive than a
    QValidator which will prevent the user from entering certain characters.

    The widget has a concept of an "initialText" which can be something like
    "<Enter name here>". This results in state 'DisplayingInitialText', which
    is not valid, but is not marked red.
*/

namespace Utils {

struct BaseValidatingLineEditPrivate {
    explicit BaseValidatingLineEditPrivate(const QWidget *w);

    const QColor m_okTextColor;
    QColor m_errorTextColor;

    BaseValidatingLineEdit::State m_state;
    QString m_errorMessage;
    QString m_initialText;
    bool m_firstChange;
};

BaseValidatingLineEditPrivate::BaseValidatingLineEditPrivate(const QWidget *w) :
    m_okTextColor(BaseValidatingLineEdit::textColor(w)),
    m_errorTextColor(Qt::red),
    m_state(BaseValidatingLineEdit::Invalid),
    m_firstChange(true)
{
}

BaseValidatingLineEdit::BaseValidatingLineEdit(QWidget *parent) :
    QLineEdit(parent),
    m_bd(new BaseValidatingLineEditPrivate(this))
{
    // Note that textChanged() is also triggered automagically by
    // QLineEdit::setText(), no need to trigger manually.
    connect(this, SIGNAL(textChanged(QString)), this, SLOT(slotChanged(QString)));
}

BaseValidatingLineEdit::~BaseValidatingLineEdit()
{
    delete m_bd;
}

QString BaseValidatingLineEdit::initialText() const
{
    return m_bd->m_initialText;
}

void BaseValidatingLineEdit::setInitialText(const QString &t)
{
    if (m_bd->m_initialText != t) {
        m_bd->m_initialText = t;
        m_bd->m_firstChange = true;
        setText(t);
    }
}

QColor BaseValidatingLineEdit::errorColor() const
{
    return m_bd->m_errorTextColor;
}

void BaseValidatingLineEdit::setErrorColor(const  QColor &c)
{
     m_bd->m_errorTextColor = c;
}

QColor BaseValidatingLineEdit::textColor(const QWidget *w)
{
    return w->palette().color(QPalette::Active, QPalette::Text);
}

void BaseValidatingLineEdit::setTextColor(QWidget *w, const QColor &c)
{
    QPalette palette = w->palette();
    palette.setColor(QPalette::Active, QPalette::Text, c);
    w->setPalette(palette);
}

BaseValidatingLineEdit::State BaseValidatingLineEdit::state() const
{
    return m_bd->m_state;
}

bool BaseValidatingLineEdit::isValid() const
{
    return m_bd->m_state == Valid;
}

QString BaseValidatingLineEdit::errorMessage() const
{
    return m_bd->m_errorMessage;
}

void BaseValidatingLineEdit::slotChanged(const QString &t)
{
    m_bd->m_errorMessage.clear();
    // Are we displaying the initial text?
    const bool isDisplayingInitialText = !m_bd->m_initialText.isEmpty() && t == m_bd->m_initialText;
    const State newState = isDisplayingInitialText ?
                               DisplayingInitialText :
                               (validate(t, &m_bd->m_errorMessage) ? Valid : Invalid);
    setToolTip(m_bd->m_errorMessage);
    if (debug)
        qDebug() << Q_FUNC_INFO << t << "State" <<  m_bd->m_state << "->" << newState << m_bd->m_errorMessage;
    // Changed..figure out if valid changed. DisplayingInitialText is not valid,
    // but should not show error color. Also trigger on the first change.
    if (newState != m_bd->m_state || m_bd->m_firstChange) {
        const bool validHasChanged = (m_bd->m_state == Valid) != (newState == Valid);
        m_bd->m_state = newState;
        m_bd->m_firstChange = false;
        setTextColor(this, newState == Invalid ? m_bd->m_errorTextColor : m_bd->m_okTextColor);
        if (validHasChanged) {
            emit validChanged(newState == Valid);
            emit validChanged();
        }
    }
    bool block = blockSignals(true);
    const QString fixedString = fixInputString(t);
    if (t != fixedString) {
        const int cursorPos = cursorPosition();
        setText(fixedString);
        setCursorPosition(qMin(cursorPos, fixedString.length()));
    }
    blockSignals(block);
}

void BaseValidatingLineEdit::slotReturnPressed()
{
    if (isValid())
        emit validReturnPressed();
}

void BaseValidatingLineEdit::triggerChanged()
{
    slotChanged(text());
}

QString BaseValidatingLineEdit::fixInputString(const QString &string)
{
    return string;
}

} // namespace Utils
<|endoftext|>


<commit_before>#include <sirius.h>

using namespace sirius;

void test_hloc(std::vector<int> mpi_grid_dims__, double cutoff__, int num_bands__,
               int num_fft_streams__, int num_threads_fft__, int use_gpu, double gpu_workload__)
{
    MPI_grid mpi_grid(mpi_grid_dims__, mpi_comm_world);

    matrix3d<double> M;
    M(0, 0) = M(1, 1) = M(2, 2) = 1.0;
    FFT3D_grid fft_grid(2.01 * cutoff__, M);

    FFT3D_context fft_ctx(mpi_grid, fft_grid, num_fft_streams__, num_threads_fft__,
                          static_cast<processing_unit_t>(use_gpu), gpu_workload__);

    Gvec gvec(vector3d<double>(0, 0, 0), M, cutoff__, fft_grid, mpi_grid.communicator(1 << 1),
              mpi_grid.communicator(1 << 0).size(), false, false);

    std::vector<double> pw_ekin(gvec.num_gvec(), 0);
    std::vector<double> veff(fft_ctx.fft()->local_size(), 2.0);

    if (mpi_comm_world.rank() == 0)
    {
        printf("total number of G-vectors: %i\n", gvec.num_gvec());
        printf("local number of G-vectors: %i\n", gvec.num_gvec(0));
        printf("FFT grid size: %i %i %i\n", fft_grid.size(0), fft_grid.size(1), fft_grid.size(2));
        printf("number of FFT streams: %i\n", fft_ctx.num_fft_streams());
    }

    fft_ctx.allocate_workspace();

    Hloc_operator hloc(fft_ctx, gvec, pw_ekin, veff);

    Wave_functions<false> phi(4 * num_bands__, gvec, mpi_grid, static_cast<processing_unit_t>(use_gpu));
    for (int i = 0; i < 4 * num_bands__; i++)
    {
        for (int j = 0; j < phi.num_gvec_loc(); j++)
        {
            phi(j, i) = type_wrapper<double_complex>::random();
        }
    }
    Wave_functions<false> hphi(4 * num_bands__, num_bands__, gvec, mpi_grid, static_cast<processing_unit_t>(use_gpu));

    Timer t1("h_loc");
    for (int i = 0; i < 4; i++)
    {
        hphi.copy_from(phi, i * num_bands__, num_bands__);
        hloc.apply(hphi, i * num_bands__, num_bands__);
    }
    t1.stop();

    double diff = 0;
    for (int i = 0; i < 4 * num_bands__; i++)
    {
        for (int j = 0; j < phi.num_gvec_loc(); j++)
        {
            diff += std::abs(2.0 * phi(j, i) - hphi(j, i));
        }
    }
    mpi_comm_world.allreduce(&diff, 1);
    if (mpi_comm_world.rank() == 0)
    {
        printf("diff: %18.12f\n", diff);
    }

    fft_ctx.deallocate_workspace();
}

int main(int argn, char** argv)
{
    cmd_args args;
    args.register_key("--help", "print this help and exit");
    args.register_key("--mpi_grid_dims=", "{int int} dimensions of MPI grid");
    args.register_key("--num_fft_streams=", "{int} number of independent FFT streams");
    args.register_key("--num_threads_fft=", "{int} number of threads for each FFT");
    args.register_key("--cutoff=", "{double} wave-functions cutoff");
    args.register_key("--num_bands=", "{int} number of bands");
    args.register_key("--use_gpu=", "{int} 0: CPU only, 1: hybrid CPU+GPU");
    args.register_key("--gpu_workload=", "{double} worload of GPU");

    args.parse_args(argn, argv);
    if (args.exist("help"))
    {
        printf("Usage: %s [options]\n", argv[0]);
        args.print_help();
        exit(0);
    }
    auto mpi_grid_dims = args.value< std::vector<int> >("mpi_grid_dims", {1, 1});
    auto num_fft_streams = args.value<int>("num_fft_streams", 1);
    auto num_threads_fft = args.value<int>("num_threads_fft", omp_get_max_threads());
    auto cutoff = args.value<double>("cutoff", 2.0);
    auto num_bands = args.value<int>("num_bands", 10);
    auto use_gpu = args.value<int>("use_gpu", 0);
    auto gpu_workload = args.value<double>("gpu_workload", 0.8);

    Platform::initialize(1);
    test_hloc(mpi_grid_dims, cutoff, num_bands, num_fft_streams, num_threads_fft, use_gpu, gpu_workload);
    mpi_comm_world.barrier();
    Timer::print();
    Platform::finalize();
}
<commit_msg>fix in a test<commit_after>#include <sirius.h>

using namespace sirius;

void test_hloc(std::vector<int> mpi_grid_dims__, double cutoff__, int num_bands__,
               int num_fft_streams__, int num_threads_fft__, int use_gpu, double gpu_workload__)
{
    MPI_grid mpi_grid(mpi_grid_dims__, mpi_comm_world);

    matrix3d<double> M;
    M(0, 0) = M(1, 1) = M(2, 2) = 1.0;
    FFT3D_grid fft_grid(2.01 * cutoff__, M);

    FFT3D_context fft_ctx(mpi_grid, fft_grid, num_fft_streams__, num_threads_fft__,
                          static_cast<processing_unit_t>(use_gpu), gpu_workload__);

    Gvec gvec(vector3d<double>(0, 0, 0), M, cutoff__, fft_grid, mpi_grid.communicator(1 << 1),
              mpi_grid.communicator(1 << 0).size(), false, false);

    std::vector<double> pw_ekin(gvec.num_gvec(), 0);
    std::vector<double> veff(fft_ctx.fft()->local_size(), 2.0);

    if (mpi_comm_world.rank() == 0)
    {
        printf("total number of G-vectors: %i\n", gvec.num_gvec());
        printf("local number of G-vectors: %i\n", gvec.num_gvec(0));
        printf("FFT grid size: %i %i %i\n", fft_grid.size(0), fft_grid.size(1), fft_grid.size(2));
        printf("number of FFT streams: %i\n", fft_ctx.num_fft_streams());
    }

    fft_ctx.allocate_workspace();

    Hloc_operator hloc(fft_ctx, gvec, pw_ekin, veff);

    Wave_functions<false> phi(4 * num_bands__, gvec, mpi_grid, CPU);
    for (int i = 0; i < 4 * num_bands__; i++)
    {
        for (int j = 0; j < phi.num_gvec_loc(); j++)
        {
            phi(j, i) = type_wrapper<double_complex>::random();
        }
    }
    Wave_functions<false> hphi(4 * num_bands__, num_bands__, gvec, mpi_grid, CPU);

    Timer t1("h_loc");
    for (int i = 0; i < 4; i++)
    {
        hphi.copy_from(phi, i * num_bands__, num_bands__);
        hloc.apply(hphi, i * num_bands__, num_bands__);
    }
    t1.stop();

    double diff = 0;
    for (int i = 0; i < 4 * num_bands__; i++)
    {
        for (int j = 0; j < phi.num_gvec_loc(); j++)
        {
            diff += std::abs(2.0 * phi(j, i) - hphi(j, i));
        }
    }
    mpi_comm_world.allreduce(&diff, 1);
    if (mpi_comm_world.rank() == 0)
    {
        printf("diff: %18.12f\n", diff);
    }

    fft_ctx.deallocate_workspace();
}

int main(int argn, char** argv)
{
    cmd_args args;
    args.register_key("--help", "print this help and exit");
    args.register_key("--mpi_grid_dims=", "{int int} dimensions of MPI grid");
    args.register_key("--num_fft_streams=", "{int} number of independent FFT streams");
    args.register_key("--num_threads_fft=", "{int} number of threads for each FFT");
    args.register_key("--cutoff=", "{double} wave-functions cutoff");
    args.register_key("--num_bands=", "{int} number of bands");
    args.register_key("--use_gpu=", "{int} 0: CPU only, 1: hybrid CPU+GPU");
    args.register_key("--gpu_workload=", "{double} worload of GPU");

    args.parse_args(argn, argv);
    if (args.exist("help"))
    {
        printf("Usage: %s [options]\n", argv[0]);
        args.print_help();
        exit(0);
    }
    auto mpi_grid_dims = args.value< std::vector<int> >("mpi_grid_dims", {1, 1});
    auto num_fft_streams = args.value<int>("num_fft_streams", 1);
    auto num_threads_fft = args.value<int>("num_threads_fft", omp_get_max_threads());
    auto cutoff = args.value<double>("cutoff", 2.0);
    auto num_bands = args.value<int>("num_bands", 10);
    auto use_gpu = args.value<int>("use_gpu", 0);
    auto gpu_workload = args.value<double>("gpu_workload", 0.8);

    Platform::initialize(1);
    test_hloc(mpi_grid_dims, cutoff, num_bands, num_fft_streams, num_threads_fft, use_gpu, gpu_workload);
    mpi_comm_world.barrier();
    Timer::print();
    Platform::finalize();
}
<|endoftext|>


<commit_before>/**
 * @file regularized_svd_test.cpp
 * @author Siddharth Agrawal
 *
 * Test the RegularizedSVDFunction class.
 */
#include <mlpack/core.hpp>
#include <mlpack/methods/regularized_svd/regularized_svd.hpp>

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace mlpack;
using namespace mlpack::svd;

BOOST_AUTO_TEST_SUITE(RegularizedSVDTest);

BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionRandomEvaluate)
{
  // Define useful constants.
  const size_t numUsers = 100;
  const size_t numItems = 100;
  const size_t numRatings = 1000;
  const size_t maxRating = 5;
  const size_t rank = 10;
  const size_t numTrials = 50;

  // Make a random rating dataset.
  arma::mat data = arma::randu(3, numRatings);
  data.row(0) = floor(data.row(0) * numUsers);
  data.row(1) = floor(data.row(1) * numItems);
  data.row(2) = floor(data.row(2) * maxRating + 0.5);

  // Manually set last row to maximum user and maximum item.
  data(0, numRatings - 1) = numUsers - 1;
  data(1, numRatings - 1) = numItems - 1;

  // Make a RegularizedSVDFunction with zero regularization.
  RegularizedSVDFunction rSVDFunc(data, rank, 0);

  for (size_t i = 0; i < numTrials; i++)
  {
    arma::mat parameters = arma::randu(rank, numUsers + numItems);

    // Calculate cost by summing up cost of each example.
    double cost = 0;
    for (size_t j = 0; j < numRatings; j++)
    {
      const size_t user = data(0, j);
      const size_t item = data(1, j) + numUsers;

      const double rating = data(2, j);
      const double ratingError = rating - arma::dot(parameters.col(user),
                                                    parameters.col(item));
      const double ratingErrorSquared = ratingError * ratingError;

      cost += ratingErrorSquared;
    }

    // Compare calculated cost and value obtained using Evaluate().
    BOOST_REQUIRE_CLOSE(cost, rSVDFunc.Evaluate(parameters), 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionRegularizationEvaluate)
{
  // Define useful constants.
  const size_t numUsers = 100;
  const size_t numItems = 100;
  const size_t numRatings = 1000;
  const size_t maxRating = 5;
  const size_t rank = 10;
  const size_t numTrials = 50;

  // Make a random rating dataset.
  arma::mat data = arma::randu(3, numRatings);
  data.row(0) = floor(data.row(0) * numUsers);
  data.row(1) = floor(data.row(1) * numItems);
  data.row(2) = floor(data.row(2) * maxRating + 0.5);

  // Manually set last row to maximum user and maximum item.
  data(0, numRatings - 1) = numUsers - 1;
  data(1, numRatings - 1) = numItems - 1;

  // Make three RegularizedSVDFunction objects with different amounts of
  // regularization.
  RegularizedSVDFunction rSVDFuncNoReg(data, rank, 0);
  RegularizedSVDFunction rSVDFuncSmallReg(data, rank, 0.5);
  RegularizedSVDFunction rSVDFuncBigReg(data, rank, 20);

  for (size_t i = 0; i < numTrials; i++)
  {
    arma::mat parameters = arma::randu(rank, numUsers + numItems);

    // Calculate the regularization contributions of parameters corresponding to
    // each rating and sum them up.
    double smallRegTerm = 0;
    double bigRegTerm = 0;
    for (size_t j = 0; j < numRatings; j++)
    {
      const size_t user = data(0, j);
      const size_t item = data(1, j) + numUsers;

      const double userVecNorm = arma::norm(parameters.col(user), 2);
      const double itemVecNorm = arma::norm(parameters.col(item), 2);
      smallRegTerm += 0.5 * (userVecNorm * userVecNorm +
                             itemVecNorm * itemVecNorm);
      bigRegTerm += 20 * (userVecNorm * userVecNorm +
                          itemVecNorm * itemVecNorm);
    }

    // Cost with regularization should be close to the sum of cost without
    // regularization and the regularization terms.
    BOOST_REQUIRE_CLOSE(rSVDFuncNoReg.Evaluate(parameters) + smallRegTerm,
        rSVDFuncSmallReg.Evaluate(parameters), 1e-5);
    BOOST_REQUIRE_CLOSE(rSVDFuncNoReg.Evaluate(parameters) + bigRegTerm,
        rSVDFuncBigReg.Evaluate(parameters), 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionGradient)
{
  // Define useful constants.
  const size_t numUsers = 50;
  const size_t numItems = 50;
  const size_t numRatings = 100;
  const size_t maxRating = 5;
  const size_t rank = 10;

  // Make a random rating dataset.
  arma::mat data = arma::randu(3, numRatings);
  data.row(0) = floor(data.row(0) * numUsers);
  data.row(1) = floor(data.row(1) * numItems);
  data.row(2) = floor(data.row(2) * maxRating + 0.5);

  // Manually set last row to maximum user and maximum item.
  data(0, numRatings - 1) = numUsers - 1;
  data(1, numRatings - 1) = numItems - 1;

  arma::mat parameters = arma::randu(rank, numUsers + numItems);

  // Make two RegularizedSVDFunction objects, one with regularization and one
  // without.
  RegularizedSVDFunction rSVDFunc1(data, rank, 0);
  RegularizedSVDFunction rSVDFunc2(data, rank, 0.5);

  // Calculate gradients for both the objects.
  arma::mat gradient1, gradient2;
  rSVDFunc1.Gradient(parameters, gradient1);
  rSVDFunc2.Gradient(parameters, gradient2);

  // Perturbation constant.
  const double epsilon = 0.0001;
  double costPlus1, costMinus1, numGradient1;
  double costPlus2, costMinus2, numGradient2;

  for (size_t i = 0; i < rank; i++)
  {
    for (size_t j = 0; j < numUsers + numItems; j++)
    {
      // Perturb parameter with a positive constant and get costs.
      parameters(i, j) += epsilon;
      costPlus1 = rSVDFunc1.Evaluate(parameters);
      costPlus2 = rSVDFunc2.Evaluate(parameters);

      // Perturb parameter with a negative constant and get costs.
      parameters(i, j) -= 2 * epsilon;
      costMinus1 = rSVDFunc1.Evaluate(parameters);
      costMinus2 = rSVDFunc2.Evaluate(parameters);

      // Compute numerical gradients using the costs calculated above.
      numGradient1 = (costPlus1 - costMinus1) / (2 * epsilon);
      numGradient2 = (costPlus2 - costMinus2) / (2 * epsilon);

      // Restore the parameter value.
      parameters(i, j) += epsilon;

      // Compare numerical and backpropagation gradient values.
      BOOST_REQUIRE_CLOSE(numGradient1, gradient1(i, j), 1e-2);
      BOOST_REQUIRE_CLOSE(numGradient2, gradient2(i, j), 1e-2);
    }
  }
}

BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionOptimize)
{
  // Define useful constants.
  const size_t numUsers = 50;
  const size_t numItems = 50;
  const size_t numRatings = 100;
  const size_t iterations = 30;
  const size_t rank = 10;
  const double alpha = 0.01;
  const double lambda = 0.01;

  // Initiate random parameters.
  arma::mat parameters = arma::randu(rank, numUsers + numItems);

  // Make a random rating dataset.
  arma::mat data = arma::randu(3, numRatings);
  data.row(0) = floor(data.row(0) * numUsers);
  data.row(1) = floor(data.row(1) * numItems);

  // Manually set last row to maximum user and maximum item.
  data(0, numRatings - 1) = numUsers - 1;
  data(1, numRatings - 1) = numItems - 1;

  // Make rating entries based on the parameters.
  for (size_t i = 0; i < numRatings; i++)
  {
    data(2, i) = arma::dot(parameters.col(data(0, i)),
                           parameters.col(numUsers + data(1, i)));
  }

  // Make the Reg SVD function and the optimizer.
  RegularizedSVDFunction rSVDFunc(data, rank, lambda);
  mlpack::optimization::SGD<RegularizedSVDFunction> optimizer(rSVDFunc,
      alpha, iterations * numRatings);

  // Obtain optimized parameters after training.
  arma::mat optParameters = arma::randu(rank, numUsers + numItems);
  optimizer.Optimize(optParameters);

  // Get predicted ratings from optimized parameters.
  arma::mat predictedData(1, numRatings);
  for (size_t i = 0; i < numRatings; i++)
  {
    predictedData(0, i) = arma::dot(optParameters.col(data(0, i)),
                                    optParameters.col(numUsers + data(1, i)));
  }

  // Calculate relative error.
  const double relativeError = arma::norm(data.row(2) - predictedData, "frob") /
                               arma::norm(data, "frob");

  // Relative error should be small.
  BOOST_REQUIRE_SMALL(relativeError, 1e-2);
}

BOOST_AUTO_TEST_SUITE_END();
<commit_msg>If gradient2 or gradient1 are zero, then BOOST_REQUIRE_CLOSE will fail, so use BOOST_REQUIRE_SMALL in those situations.<commit_after>/**
 * @file regularized_svd_test.cpp
 * @author Siddharth Agrawal
 *
 * Test the RegularizedSVDFunction class.
 */
#include <mlpack/core.hpp>
#include <mlpack/methods/regularized_svd/regularized_svd.hpp>

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace mlpack;
using namespace mlpack::svd;

BOOST_AUTO_TEST_SUITE(RegularizedSVDTest);

BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionRandomEvaluate)
{
  // Define useful constants.
  const size_t numUsers = 100;
  const size_t numItems = 100;
  const size_t numRatings = 1000;
  const size_t maxRating = 5;
  const size_t rank = 10;
  const size_t numTrials = 50;

  // Make a random rating dataset.
  arma::mat data = arma::randu(3, numRatings);
  data.row(0) = floor(data.row(0) * numUsers);
  data.row(1) = floor(data.row(1) * numItems);
  data.row(2) = floor(data.row(2) * maxRating + 0.5);

  // Manually set last row to maximum user and maximum item.
  data(0, numRatings - 1) = numUsers - 1;
  data(1, numRatings - 1) = numItems - 1;

  // Make a RegularizedSVDFunction with zero regularization.
  RegularizedSVDFunction rSVDFunc(data, rank, 0);

  for (size_t i = 0; i < numTrials; i++)
  {
    arma::mat parameters = arma::randu(rank, numUsers + numItems);

    // Calculate cost by summing up cost of each example.
    double cost = 0;
    for (size_t j = 0; j < numRatings; j++)
    {
      const size_t user = data(0, j);
      const size_t item = data(1, j) + numUsers;

      const double rating = data(2, j);
      const double ratingError = rating - arma::dot(parameters.col(user),
                                                    parameters.col(item));
      const double ratingErrorSquared = ratingError * ratingError;

      cost += ratingErrorSquared;
    }

    // Compare calculated cost and value obtained using Evaluate().
    BOOST_REQUIRE_CLOSE(cost, rSVDFunc.Evaluate(parameters), 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionRegularizationEvaluate)
{
  // Define useful constants.
  const size_t numUsers = 100;
  const size_t numItems = 100;
  const size_t numRatings = 1000;
  const size_t maxRating = 5;
  const size_t rank = 10;
  const size_t numTrials = 50;

  // Make a random rating dataset.
  arma::mat data = arma::randu(3, numRatings);
  data.row(0) = floor(data.row(0) * numUsers);
  data.row(1) = floor(data.row(1) * numItems);
  data.row(2) = floor(data.row(2) * maxRating + 0.5);

  // Manually set last row to maximum user and maximum item.
  data(0, numRatings - 1) = numUsers - 1;
  data(1, numRatings - 1) = numItems - 1;

  // Make three RegularizedSVDFunction objects with different amounts of
  // regularization.
  RegularizedSVDFunction rSVDFuncNoReg(data, rank, 0);
  RegularizedSVDFunction rSVDFuncSmallReg(data, rank, 0.5);
  RegularizedSVDFunction rSVDFuncBigReg(data, rank, 20);

  for (size_t i = 0; i < numTrials; i++)
  {
    arma::mat parameters = arma::randu(rank, numUsers + numItems);

    // Calculate the regularization contributions of parameters corresponding to
    // each rating and sum them up.
    double smallRegTerm = 0;
    double bigRegTerm = 0;
    for (size_t j = 0; j < numRatings; j++)
    {
      const size_t user = data(0, j);
      const size_t item = data(1, j) + numUsers;

      const double userVecNorm = arma::norm(parameters.col(user), 2);
      const double itemVecNorm = arma::norm(parameters.col(item), 2);
      smallRegTerm += 0.5 * (userVecNorm * userVecNorm +
                             itemVecNorm * itemVecNorm);
      bigRegTerm += 20 * (userVecNorm * userVecNorm +
                          itemVecNorm * itemVecNorm);
    }

    // Cost with regularization should be close to the sum of cost without
    // regularization and the regularization terms.
    BOOST_REQUIRE_CLOSE(rSVDFuncNoReg.Evaluate(parameters) + smallRegTerm,
        rSVDFuncSmallReg.Evaluate(parameters), 1e-5);
    BOOST_REQUIRE_CLOSE(rSVDFuncNoReg.Evaluate(parameters) + bigRegTerm,
        rSVDFuncBigReg.Evaluate(parameters), 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionGradient)
{
  // Define useful constants.
  const size_t numUsers = 50;
  const size_t numItems = 50;
  const size_t numRatings = 100;
  const size_t maxRating = 5;
  const size_t rank = 10;

  // Make a random rating dataset.
  arma::mat data = arma::randu(3, numRatings);
  data.row(0) = floor(data.row(0) * numUsers);
  data.row(1) = floor(data.row(1) * numItems);
  data.row(2) = floor(data.row(2) * maxRating + 0.5);

  // Manually set last row to maximum user and maximum item.
  data(0, numRatings - 1) = numUsers - 1;
  data(1, numRatings - 1) = numItems - 1;

  arma::mat parameters = arma::randu(rank, numUsers + numItems);

  // Make two RegularizedSVDFunction objects, one with regularization and one
  // without.
  RegularizedSVDFunction rSVDFunc1(data, rank, 0);
  RegularizedSVDFunction rSVDFunc2(data, rank, 0.5);

  // Calculate gradients for both the objects.
  arma::mat gradient1, gradient2;
  rSVDFunc1.Gradient(parameters, gradient1);
  rSVDFunc2.Gradient(parameters, gradient2);

  // Perturbation constant.
  const double epsilon = 0.0001;
  double costPlus1, costMinus1, numGradient1;
  double costPlus2, costMinus2, numGradient2;

  for (size_t i = 0; i < rank; i++)
  {
    for (size_t j = 0; j < numUsers + numItems; j++)
    {
      // Perturb parameter with a positive constant and get costs.
      parameters(i, j) += epsilon;
      costPlus1 = rSVDFunc1.Evaluate(parameters);
      costPlus2 = rSVDFunc2.Evaluate(parameters);

      // Perturb parameter with a negative constant and get costs.
      parameters(i, j) -= 2 * epsilon;
      costMinus1 = rSVDFunc1.Evaluate(parameters);
      costMinus2 = rSVDFunc2.Evaluate(parameters);

      // Compute numerical gradients using the costs calculated above.
      numGradient1 = (costPlus1 - costMinus1) / (2 * epsilon);
      numGradient2 = (costPlus2 - costMinus2) / (2 * epsilon);

      // Restore the parameter value.
      parameters(i, j) += epsilon;

      // Compare numerical and backpropagation gradient values.
      if (gradient1(i, j) == 0.0)
        BOOST_REQUIRE_SMALL(numGradient1, 1e-5);
      else
        BOOST_REQUIRE_CLOSE(numGradient1, gradient1(i, j), 1e-2);

      if (graident2(i, j) == 0.0)
        BOOST_REQUIRE_SMALL(numGradient2, 1e-5);
      else
        BOOST_REQUIRE_CLOSE(numGradient2, gradient2(i, j), 1e-2);
    }
  }
}

BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionOptimize)
{
  // Define useful constants.
  const size_t numUsers = 50;
  const size_t numItems = 50;
  const size_t numRatings = 100;
  const size_t iterations = 30;
  const size_t rank = 10;
  const double alpha = 0.01;
  const double lambda = 0.01;

  // Initiate random parameters.
  arma::mat parameters = arma::randu(rank, numUsers + numItems);

  // Make a random rating dataset.
  arma::mat data = arma::randu(3, numRatings);
  data.row(0) = floor(data.row(0) * numUsers);
  data.row(1) = floor(data.row(1) * numItems);

  // Manually set last row to maximum user and maximum item.
  data(0, numRatings - 1) = numUsers - 1;
  data(1, numRatings - 1) = numItems - 1;

  // Make rating entries based on the parameters.
  for (size_t i = 0; i < numRatings; i++)
  {
    data(2, i) = arma::dot(parameters.col(data(0, i)),
                           parameters.col(numUsers + data(1, i)));
  }

  // Make the Reg SVD function and the optimizer.
  RegularizedSVDFunction rSVDFunc(data, rank, lambda);
  mlpack::optimization::SGD<RegularizedSVDFunction> optimizer(rSVDFunc,
      alpha, iterations * numRatings);

  // Obtain optimized parameters after training.
  arma::mat optParameters = arma::randu(rank, numUsers + numItems);
  optimizer.Optimize(optParameters);

  // Get predicted ratings from optimized parameters.
  arma::mat predictedData(1, numRatings);
  for (size_t i = 0; i < numRatings; i++)
  {
    predictedData(0, i) = arma::dot(optParameters.col(data(0, i)),
                                    optParameters.col(numUsers + data(1, i)));
  }

  // Calculate relative error.
  const double relativeError = arma::norm(data.row(2) - predictedData, "frob") /
                               arma::norm(data, "frob");

  // Relative error should be small.
  BOOST_REQUIRE_SMALL(relativeError, 1e-2);
}

BOOST_AUTO_TEST_SUITE_END();
<|endoftext|>


<commit_before>/*
 * SSL and TLS filter.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "ssl_filter.hxx"
#include "ssl_factory.hxx"
#include "ssl_config.hxx"
#include "ssl_quark.hxx"
#include "notify.h"
#include "pool.h"
#include "fifo-buffer.h"
#include "buffered_io.h"
#include "gerrno.h"
#include "fb_pool.h"

#include <openssl/ssl.h>
#include <openssl/err.h>

#include <pthread.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
#include <sys/socket.h>

struct ssl_filter {
    struct pool *pool;

    struct notify *notify;

    int encrypted_fd, plain_fd;

    struct fifo_buffer *from_encrypted, *from_plain;

    SSL *ssl;

    char *peer_subject, *peer_issuer_subject;

    pthread_mutex_t mutex;
    pthread_t thread;

    bool closing;
};

static inline void
ssl_filter_lock(struct ssl_filter *ssl)
{
    pthread_mutex_lock(&ssl->mutex);
}

static inline void
ssl_filter_unlock(struct ssl_filter *ssl)
{
    pthread_mutex_unlock(&ssl->mutex);
}

static void
ssl_set_error(GError **error_r)
{
    if (error_r == NULL)
        return;

    unsigned long error = ERR_get_error();
    char buffer[120];
    g_set_error(error_r, ssl_quark(), 0, "%s",
                ERR_error_string(error, buffer));
}

/**
 * Close both sockets.
 *
 * The #ssl_filter object must be locked by the caller.
 */
static void
ssl_filter_close_sockets(struct ssl_filter *ssl)
{
    ssl->closing = true;

    if (ssl->encrypted_fd >= 0) {
        close(ssl->encrypted_fd);
        ssl->encrypted_fd = -1;
    }

    if (ssl->plain_fd >= 0) {
        close(ssl->plain_fd);
        ssl->plain_fd = -1;
    }
}

/**
 * Shut down both sockets.  This is used to wake up the thread; note
 * that closing the file descriptors will not make poll() return.
 *
 * The #ssl_filter object must be locked by the caller.
 */
static void
ssl_filter_shutdown_sockets(struct ssl_filter *ssl)
{
    ssl->closing = true;

    if (ssl->encrypted_fd >= 0)
        shutdown(ssl->encrypted_fd, SHUT_RDWR);

    if (ssl->plain_fd >= 0)
        shutdown(ssl->plain_fd, SHUT_RDWR);
}

/**
 * Wait for events on the encrypted socket.
 *
 * The #ssl_filter object must be locked by the caller.
 */
static short
ssl_poll(struct ssl_filter *ssl, short events, int timeout_ms,
         GError **error_r)
{
    struct pollfd pfd = {
        ssl->encrypted_fd,
        events,
        0,
    };

    ssl_filter_unlock(ssl);
    int ret = poll(&pfd, 1, timeout_ms);
    ssl_filter_lock(ssl);
    if (ssl->closing)
        return 0;
    else if (ret > 0)
        return pfd.revents;
    else if (ret == 0) {
        g_set_error(error_r, ssl_quark(), 0, "Timeout");
        return 0;
    } else {
        set_error_errno_msg(error_r, "poll() failed");
        return 0;
    }
}

static bool
ssl_filter_do_handshake(struct ssl_filter *ssl, GError **error_r)
{
    while (!ssl->closing) {
        assert(ssl->encrypted_fd >= 0);

        ERR_clear_error();
        int ret = SSL_do_handshake(ssl->ssl);
        if (ret == 1)
            return true;

        if (ret == 0) {
            ssl_set_error(error_r);
            return false;
        }

        int error = SSL_get_error(ssl->ssl, ret);
        if (error == SSL_ERROR_WANT_READ) {
            if (ssl_poll(ssl, POLLIN, -1, error_r) == 0)
                return false;
        } else if (error == SSL_ERROR_WANT_WRITE) {
            if (ssl_poll(ssl, POLLOUT, -1, error_r) == 0)
                return false;
        } else {
            ssl_set_error(error_r);
            return false;
        }
    }

    g_set_error(error_r, ssl_quark(), 0, "Closed");
    return false;
}

static char *
format_name(X509_NAME *name)
{
    if (name == NULL)
        return NULL;

    BIO *bio = BIO_new(BIO_s_mem());
    if (bio == NULL)
        return NULL;

    X509_NAME_print_ex(bio, name, 0,
                       ASN1_STRFLGS_UTF8_CONVERT | XN_FLAG_SEP_COMMA_PLUS);
    char buffer[1024];
    int length = BIO_read(bio, buffer, sizeof(buffer) - 1);
    BIO_free(bio);

    return strndup(buffer, length);
}

static char *
format_subject_name(X509 *cert)
{
    return format_name(X509_get_subject_name(cert));
}

static char *
format_issuer_subject_name(X509 *cert)
{
    return format_name(X509_get_issuer_name(cert));
}

gcc_const
static bool
is_ssl_error(SSL *ssl, int ret)
{
    switch (SSL_get_error(ssl, ret)) {
    case SSL_ERROR_NONE:
    case SSL_ERROR_WANT_READ:
    case SSL_ERROR_WANT_WRITE:
    case SSL_ERROR_WANT_CONNECT:
    case SSL_ERROR_WANT_ACCEPT:
        return false;

    default:
        return true;
    }
}

/**
 * @return false on error
 */
static bool
ssl_decrypt(SSL *ssl, struct fifo_buffer *buffer)
{
    size_t length;
    void *data = fifo_buffer_write(buffer, &length);
    if (buffer == NULL)
        return true;

    ERR_clear_error();
    int ret = SSL_read(ssl, data, length);
    if (ret > 0) {
        fifo_buffer_append(buffer, ret);
        return true;
    } else
        return ret < 0 && !is_ssl_error(ssl, ret);
}

/**
 * @return false on error
 */
static bool
ssl_encrypt(SSL *ssl, struct fifo_buffer *buffer)
{
    size_t length;
    const void *data = fifo_buffer_read(buffer, &length);
    if (buffer == NULL)
        return true;

    ERR_clear_error();
    int ret = SSL_write(ssl, data, length);
    if (ret > 0) {
        fifo_buffer_consume(buffer, ret);
        return true;
    } else
        return ret < 0 && !is_ssl_error(ssl, ret);
}

static void *
ssl_filter_thread(void *ctx)
{
    struct ssl_filter *ssl = (struct ssl_filter *)ctx;

    ssl_filter_lock(ssl);

    GError *error = NULL;
    if (!ssl_filter_do_handshake(ssl, &error)) {
        if (error != NULL) {
            fprintf(stderr, "%s\n", error->message);
            g_error_free(error);
        } else {
            assert(ssl->closing);
        }

        ssl_filter_close_sockets(ssl);
    }

    if (!ssl->closing) {
        X509 *cert = SSL_get_peer_certificate(ssl->ssl);
        if (cert != NULL)
            ssl->peer_subject = format_subject_name(cert);
        if (cert != NULL)
            ssl->peer_issuer_subject =
                format_issuer_subject_name(cert);
    }

    struct pollfd pfds[2] = {
        { ssl->encrypted_fd, 0, 0 },
        { ssl->plain_fd, 0, 0 },
    };

    while (!ssl->closing) {
        assert(ssl->encrypted_fd >= 0);
        assert(ssl->plain_fd >= 0);

        pfds[0].events = pfds[1].events = 0;
        pfds[0].revents = pfds[1].revents = 0;

        if (!fifo_buffer_full(ssl->from_encrypted))
            pfds[0].events |= POLLIN;

        if (!fifo_buffer_empty(ssl->from_encrypted))
            pfds[1].events |= POLLOUT;

        if (!fifo_buffer_full(ssl->from_plain))
            pfds[1].events |= POLLIN;

        if (!fifo_buffer_empty(ssl->from_plain))
            pfds[0].events |= POLLOUT;

        struct pollfd *p;
        nfds_t nfds;
        if (pfds[0].events != 0) {
            p = pfds;
            nfds = pfds[1].events != 0 ? 2 : 1;
        } else {
            assert(pfds[1].events != 0);
            p = pfds + 1;
            nfds = 1;
        }

        ssl_filter_unlock(ssl);
        int n = poll(p, nfds, -1);
        ssl_filter_lock(ssl);
        if (n <= 0 || ssl->closing)
            break;

        if ((pfds[1].revents & POLLIN) != 0) {
            const bool was_empty = fifo_buffer_empty(ssl->from_plain);

            ssize_t nbytes = recv_to_buffer(ssl->plain_fd, ssl->from_plain, 65536);
            assert(nbytes != -2);

            if (nbytes == 0 || (nbytes < 0 && errno != EAGAIN)) {
                close(ssl->plain_fd);
                ssl->plain_fd = -1;
                break;
            }

            if (was_empty && !fifo_buffer_empty(ssl->from_plain))
                /* try decryption again to see if OpenSSL has waits
                   for more encrypted data from us */
                pfds[0].revents |= POLLOUT;
        }

        if ((pfds[1].revents & POLLOUT) != 0) {
            const bool was_full = fifo_buffer_full(ssl->from_encrypted);

            if (send_from_buffer(ssl->plain_fd, ssl->from_encrypted) < 0 &&
                errno != EAGAIN) {
                close(ssl->plain_fd);
                ssl->plain_fd = -1;
                break;
            }

            if (was_full && !fifo_buffer_full(ssl->from_encrypted))
                /* try decryption again to see if OpenSSL has more
                   decrypted data for us */
                pfds[0].revents |= POLLIN;
        }

        if ((pfds[0].revents & POLLIN) != 0) {
            assert(!fifo_buffer_full(ssl->from_encrypted));

            if (!ssl_decrypt(ssl->ssl, ssl->from_encrypted)) {
                close(ssl->encrypted_fd);
                ssl->encrypted_fd = -1;
                break;
            }
        }

        if ((pfds[0].revents & POLLOUT) != 0) {
            assert(!fifo_buffer_empty(ssl->from_plain));

            if (!ssl_encrypt(ssl->ssl, ssl->from_plain)) {
                close(ssl->encrypted_fd);
                ssl->encrypted_fd = -1;
                break;
            }
        }
    }

    ssl_filter_close_sockets(ssl);
    ssl_filter_unlock(ssl);

    ERR_clear_error();

    notify_signal(ssl->notify);
    return NULL;
}

struct ssl_filter *
ssl_filter_new(struct pool *pool, struct ssl_factory *factory,
               int encrypted_fd, int plain_fd,
               struct notify *notify,
               GError **error_r)
{
    assert(pool != NULL);
    assert(factory != NULL);

    struct ssl_filter *ssl = (struct ssl_filter *)p_malloc(pool, sizeof(*ssl));
    ssl->pool = pool;
    ssl->notify = notify;
    ssl->encrypted_fd = encrypted_fd;
    ssl->plain_fd = plain_fd;

    ssl->from_encrypted = fb_pool_alloc();
    ssl->from_plain = fb_pool_alloc();

    ssl->ssl = ssl_factory_make(factory);
    if (ssl->ssl == NULL) {
        g_set_error(error_r, ssl_quark(), 0, "SSL_new() failed");
        fb_pool_free(ssl->from_encrypted);
        fb_pool_free(ssl->from_plain);
        return NULL;
    }

    SSL_set_accept_state(ssl->ssl);
    SSL_set_fd(ssl->ssl, encrypted_fd);

    pthread_mutex_init(&ssl->mutex, NULL);

    ssl->peer_subject = NULL;
    ssl->peer_issuer_subject = NULL;
    ssl->closing = false;

    int error = pthread_create(&ssl->thread, NULL, ssl_filter_thread, ssl);
    if (error != 0) {
        SSL_free(ssl->ssl);
        fb_pool_free(ssl->from_encrypted);
        fb_pool_free(ssl->from_plain);
        g_set_error(error_r, ssl_quark(), error,
                    "Failed to create thread: %s", strerror(error));
        return NULL;
    }

    return ssl;
}

void
ssl_filter_free(struct ssl_filter *ssl)
{
    assert(ssl != NULL);

    ssl_filter_lock(ssl);

    if (ssl->ssl != NULL)
        SSL_free(ssl->ssl);

    fb_pool_free(ssl->from_encrypted);
    fb_pool_free(ssl->from_plain);

    ssl_filter_shutdown_sockets(ssl);

    ssl_filter_unlock(ssl);

    pthread_join(ssl->thread, NULL);
    pthread_mutex_destroy(&ssl->mutex);

    ssl_filter_close_sockets(ssl);

    free(ssl->peer_subject);
    free(ssl->peer_issuer_subject);
}

const char *
ssl_filter_get_peer_subject(struct ssl_filter *ssl)
{
    assert(ssl != NULL);

    ssl_filter_lock(ssl);
    const char *peer_subject = ssl->peer_subject;
    ssl_filter_unlock(ssl);

    return peer_subject;
}

const char *
ssl_filter_get_peer_issuer_subject(struct ssl_filter *ssl)
{
    assert(ssl != NULL);

    ssl_filter_lock(ssl);
    const char *subject = ssl->peer_issuer_subject;
    ssl_filter_unlock(ssl);

    return subject;
}
<commit_msg>ssl_filter: remove unused attribute "pool"<commit_after>/*
 * SSL and TLS filter.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "ssl_filter.hxx"
#include "ssl_factory.hxx"
#include "ssl_config.hxx"
#include "ssl_quark.hxx"
#include "notify.h"
#include "pool.h"
#include "fifo-buffer.h"
#include "buffered_io.h"
#include "gerrno.h"
#include "fb_pool.h"

#include <openssl/ssl.h>
#include <openssl/err.h>

#include <pthread.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
#include <sys/socket.h>

struct ssl_filter {
    struct notify *notify;

    int encrypted_fd, plain_fd;

    struct fifo_buffer *from_encrypted, *from_plain;

    SSL *ssl;

    char *peer_subject, *peer_issuer_subject;

    pthread_mutex_t mutex;
    pthread_t thread;

    bool closing;
};

static inline void
ssl_filter_lock(struct ssl_filter *ssl)
{
    pthread_mutex_lock(&ssl->mutex);
}

static inline void
ssl_filter_unlock(struct ssl_filter *ssl)
{
    pthread_mutex_unlock(&ssl->mutex);
}

static void
ssl_set_error(GError **error_r)
{
    if (error_r == NULL)
        return;

    unsigned long error = ERR_get_error();
    char buffer[120];
    g_set_error(error_r, ssl_quark(), 0, "%s",
                ERR_error_string(error, buffer));
}

/**
 * Close both sockets.
 *
 * The #ssl_filter object must be locked by the caller.
 */
static void
ssl_filter_close_sockets(struct ssl_filter *ssl)
{
    ssl->closing = true;

    if (ssl->encrypted_fd >= 0) {
        close(ssl->encrypted_fd);
        ssl->encrypted_fd = -1;
    }

    if (ssl->plain_fd >= 0) {
        close(ssl->plain_fd);
        ssl->plain_fd = -1;
    }
}

/**
 * Shut down both sockets.  This is used to wake up the thread; note
 * that closing the file descriptors will not make poll() return.
 *
 * The #ssl_filter object must be locked by the caller.
 */
static void
ssl_filter_shutdown_sockets(struct ssl_filter *ssl)
{
    ssl->closing = true;

    if (ssl->encrypted_fd >= 0)
        shutdown(ssl->encrypted_fd, SHUT_RDWR);

    if (ssl->plain_fd >= 0)
        shutdown(ssl->plain_fd, SHUT_RDWR);
}

/**
 * Wait for events on the encrypted socket.
 *
 * The #ssl_filter object must be locked by the caller.
 */
static short
ssl_poll(struct ssl_filter *ssl, short events, int timeout_ms,
         GError **error_r)
{
    struct pollfd pfd = {
        ssl->encrypted_fd,
        events,
        0,
    };

    ssl_filter_unlock(ssl);
    int ret = poll(&pfd, 1, timeout_ms);
    ssl_filter_lock(ssl);
    if (ssl->closing)
        return 0;
    else if (ret > 0)
        return pfd.revents;
    else if (ret == 0) {
        g_set_error(error_r, ssl_quark(), 0, "Timeout");
        return 0;
    } else {
        set_error_errno_msg(error_r, "poll() failed");
        return 0;
    }
}

static bool
ssl_filter_do_handshake(struct ssl_filter *ssl, GError **error_r)
{
    while (!ssl->closing) {
        assert(ssl->encrypted_fd >= 0);

        ERR_clear_error();
        int ret = SSL_do_handshake(ssl->ssl);
        if (ret == 1)
            return true;

        if (ret == 0) {
            ssl_set_error(error_r);
            return false;
        }

        int error = SSL_get_error(ssl->ssl, ret);
        if (error == SSL_ERROR_WANT_READ) {
            if (ssl_poll(ssl, POLLIN, -1, error_r) == 0)
                return false;
        } else if (error == SSL_ERROR_WANT_WRITE) {
            if (ssl_poll(ssl, POLLOUT, -1, error_r) == 0)
                return false;
        } else {
            ssl_set_error(error_r);
            return false;
        }
    }

    g_set_error(error_r, ssl_quark(), 0, "Closed");
    return false;
}

static char *
format_name(X509_NAME *name)
{
    if (name == NULL)
        return NULL;

    BIO *bio = BIO_new(BIO_s_mem());
    if (bio == NULL)
        return NULL;

    X509_NAME_print_ex(bio, name, 0,
                       ASN1_STRFLGS_UTF8_CONVERT | XN_FLAG_SEP_COMMA_PLUS);
    char buffer[1024];
    int length = BIO_read(bio, buffer, sizeof(buffer) - 1);
    BIO_free(bio);

    return strndup(buffer, length);
}

static char *
format_subject_name(X509 *cert)
{
    return format_name(X509_get_subject_name(cert));
}

static char *
format_issuer_subject_name(X509 *cert)
{
    return format_name(X509_get_issuer_name(cert));
}

gcc_const
static bool
is_ssl_error(SSL *ssl, int ret)
{
    switch (SSL_get_error(ssl, ret)) {
    case SSL_ERROR_NONE:
    case SSL_ERROR_WANT_READ:
    case SSL_ERROR_WANT_WRITE:
    case SSL_ERROR_WANT_CONNECT:
    case SSL_ERROR_WANT_ACCEPT:
        return false;

    default:
        return true;
    }
}

/**
 * @return false on error
 */
static bool
ssl_decrypt(SSL *ssl, struct fifo_buffer *buffer)
{
    size_t length;
    void *data = fifo_buffer_write(buffer, &length);
    if (buffer == NULL)
        return true;

    ERR_clear_error();
    int ret = SSL_read(ssl, data, length);
    if (ret > 0) {
        fifo_buffer_append(buffer, ret);
        return true;
    } else
        return ret < 0 && !is_ssl_error(ssl, ret);
}

/**
 * @return false on error
 */
static bool
ssl_encrypt(SSL *ssl, struct fifo_buffer *buffer)
{
    size_t length;
    const void *data = fifo_buffer_read(buffer, &length);
    if (buffer == NULL)
        return true;

    ERR_clear_error();
    int ret = SSL_write(ssl, data, length);
    if (ret > 0) {
        fifo_buffer_consume(buffer, ret);
        return true;
    } else
        return ret < 0 && !is_ssl_error(ssl, ret);
}

static void *
ssl_filter_thread(void *ctx)
{
    struct ssl_filter *ssl = (struct ssl_filter *)ctx;

    ssl_filter_lock(ssl);

    GError *error = NULL;
    if (!ssl_filter_do_handshake(ssl, &error)) {
        if (error != NULL) {
            fprintf(stderr, "%s\n", error->message);
            g_error_free(error);
        } else {
            assert(ssl->closing);
        }

        ssl_filter_close_sockets(ssl);
    }

    if (!ssl->closing) {
        X509 *cert = SSL_get_peer_certificate(ssl->ssl);
        if (cert != NULL)
            ssl->peer_subject = format_subject_name(cert);
        if (cert != NULL)
            ssl->peer_issuer_subject =
                format_issuer_subject_name(cert);
    }

    struct pollfd pfds[2] = {
        { ssl->encrypted_fd, 0, 0 },
        { ssl->plain_fd, 0, 0 },
    };

    while (!ssl->closing) {
        assert(ssl->encrypted_fd >= 0);
        assert(ssl->plain_fd >= 0);

        pfds[0].events = pfds[1].events = 0;
        pfds[0].revents = pfds[1].revents = 0;

        if (!fifo_buffer_full(ssl->from_encrypted))
            pfds[0].events |= POLLIN;

        if (!fifo_buffer_empty(ssl->from_encrypted))
            pfds[1].events |= POLLOUT;

        if (!fifo_buffer_full(ssl->from_plain))
            pfds[1].events |= POLLIN;

        if (!fifo_buffer_empty(ssl->from_plain))
            pfds[0].events |= POLLOUT;

        struct pollfd *p;
        nfds_t nfds;
        if (pfds[0].events != 0) {
            p = pfds;
            nfds = pfds[1].events != 0 ? 2 : 1;
        } else {
            assert(pfds[1].events != 0);
            p = pfds + 1;
            nfds = 1;
        }

        ssl_filter_unlock(ssl);
        int n = poll(p, nfds, -1);
        ssl_filter_lock(ssl);
        if (n <= 0 || ssl->closing)
            break;

        if ((pfds[1].revents & POLLIN) != 0) {
            const bool was_empty = fifo_buffer_empty(ssl->from_plain);

            ssize_t nbytes = recv_to_buffer(ssl->plain_fd, ssl->from_plain, 65536);
            assert(nbytes != -2);

            if (nbytes == 0 || (nbytes < 0 && errno != EAGAIN)) {
                close(ssl->plain_fd);
                ssl->plain_fd = -1;
                break;
            }

            if (was_empty && !fifo_buffer_empty(ssl->from_plain))
                /* try decryption again to see if OpenSSL has waits
                   for more encrypted data from us */
                pfds[0].revents |= POLLOUT;
        }

        if ((pfds[1].revents & POLLOUT) != 0) {
            const bool was_full = fifo_buffer_full(ssl->from_encrypted);

            if (send_from_buffer(ssl->plain_fd, ssl->from_encrypted) < 0 &&
                errno != EAGAIN) {
                close(ssl->plain_fd);
                ssl->plain_fd = -1;
                break;
            }

            if (was_full && !fifo_buffer_full(ssl->from_encrypted))
                /* try decryption again to see if OpenSSL has more
                   decrypted data for us */
                pfds[0].revents |= POLLIN;
        }

        if ((pfds[0].revents & POLLIN) != 0) {
            assert(!fifo_buffer_full(ssl->from_encrypted));

            if (!ssl_decrypt(ssl->ssl, ssl->from_encrypted)) {
                close(ssl->encrypted_fd);
                ssl->encrypted_fd = -1;
                break;
            }
        }

        if ((pfds[0].revents & POLLOUT) != 0) {
            assert(!fifo_buffer_empty(ssl->from_plain));

            if (!ssl_encrypt(ssl->ssl, ssl->from_plain)) {
                close(ssl->encrypted_fd);
                ssl->encrypted_fd = -1;
                break;
            }
        }
    }

    ssl_filter_close_sockets(ssl);
    ssl_filter_unlock(ssl);

    ERR_clear_error();

    notify_signal(ssl->notify);
    return NULL;
}

struct ssl_filter *
ssl_filter_new(struct pool *pool, struct ssl_factory *factory,
               int encrypted_fd, int plain_fd,
               struct notify *notify,
               GError **error_r)
{
    assert(pool != NULL);
    assert(factory != NULL);

    struct ssl_filter *ssl = (struct ssl_filter *)p_malloc(pool, sizeof(*ssl));
    ssl->notify = notify;
    ssl->encrypted_fd = encrypted_fd;
    ssl->plain_fd = plain_fd;

    ssl->from_encrypted = fb_pool_alloc();
    ssl->from_plain = fb_pool_alloc();

    ssl->ssl = ssl_factory_make(factory);
    if (ssl->ssl == NULL) {
        g_set_error(error_r, ssl_quark(), 0, "SSL_new() failed");
        fb_pool_free(ssl->from_encrypted);
        fb_pool_free(ssl->from_plain);
        return NULL;
    }

    SSL_set_accept_state(ssl->ssl);
    SSL_set_fd(ssl->ssl, encrypted_fd);

    pthread_mutex_init(&ssl->mutex, NULL);

    ssl->peer_subject = NULL;
    ssl->peer_issuer_subject = NULL;
    ssl->closing = false;

    int error = pthread_create(&ssl->thread, NULL, ssl_filter_thread, ssl);
    if (error != 0) {
        SSL_free(ssl->ssl);
        fb_pool_free(ssl->from_encrypted);
        fb_pool_free(ssl->from_plain);
        g_set_error(error_r, ssl_quark(), error,
                    "Failed to create thread: %s", strerror(error));
        return NULL;
    }

    return ssl;
}

void
ssl_filter_free(struct ssl_filter *ssl)
{
    assert(ssl != NULL);

    ssl_filter_lock(ssl);

    if (ssl->ssl != NULL)
        SSL_free(ssl->ssl);

    fb_pool_free(ssl->from_encrypted);
    fb_pool_free(ssl->from_plain);

    ssl_filter_shutdown_sockets(ssl);

    ssl_filter_unlock(ssl);

    pthread_join(ssl->thread, NULL);
    pthread_mutex_destroy(&ssl->mutex);

    ssl_filter_close_sockets(ssl);

    free(ssl->peer_subject);
    free(ssl->peer_issuer_subject);
}

const char *
ssl_filter_get_peer_subject(struct ssl_filter *ssl)
{
    assert(ssl != NULL);

    ssl_filter_lock(ssl);
    const char *peer_subject = ssl->peer_subject;
    ssl_filter_unlock(ssl);

    return peer_subject;
}

const char *
ssl_filter_get_peer_issuer_subject(struct ssl_filter *ssl)
{
    assert(ssl != NULL);

    ssl_filter_lock(ssl);
    const char *subject = ssl->peer_issuer_subject;
    ssl_filter_unlock(ssl);

    return subject;
}
<|endoftext|>


<commit_before>
#include <osgParticle/Program>

#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>

bool  IOProgram_readLocalData(osg::Object &obj, osgDB::Input &fr);
bool  IOProgram_writeLocalData(const osg::Object &obj, osgDB::Output &fw);

osgDB::RegisterDotOsgWrapperProxy  g_IOProgramProxy
(
    0,
    "osgParicle::Program",
    "Object Node ParticleProcessor osgParicle::Program",
    IOProgram_readLocalData,
    IOProgram_writeLocalData
);

bool IOProgram_readLocalData(osg::Object &, osgDB::Input &)
{
    return false;
}

bool IOProgram_writeLocalData(const osg::Object &, osgDB::Output &)
{
    return false;
}
<commit_msg>Fixed typo<commit_after>
#include <osgParticle/Program>

#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>

bool  IOProgram_readLocalData(osg::Object &obj, osgDB::Input &fr);
bool  IOProgram_writeLocalData(const osg::Object &obj, osgDB::Output &fw);

osgDB::RegisterDotOsgWrapperProxy  g_IOProgramProxy
(
    0,
    "osgParticle::Program",
    "Object Node ParticleProcessor osgParticle::Program",
    IOProgram_readLocalData,
    IOProgram_writeLocalData
);

bool IOProgram_readLocalData(osg::Object &, osgDB::Input &)
{
    return false;
}

bool IOProgram_writeLocalData(const osg::Object &, osgDB::Output &)
{
    return false;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** 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 "searchresulttreeview.h"
#include "searchresulttreeitemroles.h"
#include "searchresulttreemodel.h"
#include "searchresulttreeitemdelegate.h"

#include <QHeaderView>
#include <QKeyEvent>

using namespace Find::Internal;

SearchResultTreeView::SearchResultTreeView(QWidget *parent)
    : QTreeView(parent)
    , m_model(new SearchResultTreeModel(this))
    , m_autoExpandResults(false)
{
    setModel(m_model);
    setItemDelegate(new SearchResultTreeItemDelegate(this));
    setIndentation(14);
    setUniformRowHeights(true);
    setExpandsOnDoubleClick(true);
    header()->hide();

    connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(emitJumpToSearchResult(QModelIndex)));
}

void SearchResultTreeView::setAutoExpandResults(bool expand)
{
    m_autoExpandResults = expand;
}

void SearchResultTreeView::setTextEditorFont(const QFont &font, const SearchResultColor color)
{
    m_model->setTextEditorFont(font, color);

    QPalette p = palette();
    p.setColor(QPalette::Base, color.textBackground);
    setPalette(p);
}

void SearchResultTreeView::clear()
{
    m_model->clear();
}

void SearchResultTreeView::addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode)
{
    QList<QModelIndex> addedParents = m_model->addResults(items, mode);
    if (m_autoExpandResults && !addedParents.isEmpty()) {
        foreach (const QModelIndex &index, addedParents)
            setExpanded(index, true);
    }
}

void SearchResultTreeView::emitJumpToSearchResult(const QModelIndex &index)
{
    if (model()->data(index, ItemDataRoles::IsGeneratedRole).toBool())
        return;
    SearchResultItem item = model()->data(index, ItemDataRoles::ResultItemRole).value<SearchResultItem>();

    emit jumpToSearchResult(item);
}

void SearchResultTreeView::keyPressEvent(QKeyEvent *e)
{
    if (!e->modifiers() && e->key() == Qt::Key_Return) {
        emit activated(currentIndex());
        e->accept();
        return;
    }
    QTreeView::keyPressEvent(e);
}

SearchResultTreeModel *SearchResultTreeView::model() const
{
    return m_model;
}
<commit_msg>Find: Another build fix for windows<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** 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 "searchresulttreeview.h"
#include "searchresulttreeitemroles.h"
#include "searchresulttreemodel.h"
#include "searchresulttreeitemdelegate.h"

#include <QHeaderView>
#include <QKeyEvent>

namespace Find {
namespace Internal {

SearchResultTreeView::SearchResultTreeView(QWidget *parent)
    : QTreeView(parent)
    , m_model(new SearchResultTreeModel(this))
    , m_autoExpandResults(false)
{
    setModel(m_model);
    setItemDelegate(new SearchResultTreeItemDelegate(this));
    setIndentation(14);
    setUniformRowHeights(true);
    setExpandsOnDoubleClick(true);
    header()->hide();

    connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(emitJumpToSearchResult(QModelIndex)));
}

void SearchResultTreeView::setAutoExpandResults(bool expand)
{
    m_autoExpandResults = expand;
}

void SearchResultTreeView::setTextEditorFont(const QFont &font, const SearchResultColor color)
{
    m_model->setTextEditorFont(font, color);

    QPalette p = palette();
    p.setColor(QPalette::Base, color.textBackground);
    setPalette(p);
}

void SearchResultTreeView::clear()
{
    m_model->clear();
}

void SearchResultTreeView::addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode)
{
    QList<QModelIndex> addedParents = m_model->addResults(items, mode);
    if (m_autoExpandResults && !addedParents.isEmpty()) {
        foreach (const QModelIndex &index, addedParents)
            setExpanded(index, true);
    }
}

void SearchResultTreeView::emitJumpToSearchResult(const QModelIndex &index)
{
    if (model()->data(index, ItemDataRoles::IsGeneratedRole).toBool())
        return;
    SearchResultItem item = model()->data(index, ItemDataRoles::ResultItemRole).value<SearchResultItem>();

    emit jumpToSearchResult(item);
}

void SearchResultTreeView::keyPressEvent(QKeyEvent *e)
{
    if (!e->modifiers() && e->key() == Qt::Key_Return) {
        emit activated(currentIndex());
        e->accept();
        return;
    }
    QTreeView::keyPressEvent(e);
}

SearchResultTreeModel *SearchResultTreeView::model() const
{
    return m_model;
}

} // namespace Internal
} // namespace Find
<|endoftext|>


<commit_before>/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file.  Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.2, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/

#include "changeselectiondialog.h"

#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>

using namespace Git::Internal;

ChangeSelectionDialog::ChangeSelectionDialog(QWidget *parent)
    : QDialog(parent)
{
    m_ui.setupUi(this);
    connect(m_ui.repositoryButton, SIGNAL(clicked()), this, SLOT(selectWorkingDirectory()));
}

void ChangeSelectionDialog::selectWorkingDirectory()
{
    static QString location = QString();
    location = QFileDialog::getExistingDirectory(this,
                                      QLatin1String("Select Git repository"),
                                      location);
    if (location.isEmpty())
        return;

    // Verify that the location is a repository
    // We are polite, we also allow to specify a directory, which is not
    // the head directory of the repository.
    QDir repository(location);
    do {
        if (repository.entryList(QDir::AllDirs).contains(QLatin1String(".git"))) {
            m_ui.repositoryEdit->setText(repository.absolutePath());
            return;
        }
    } while (repository.cdUp());

    // Did not find a repo
    QMessageBox::critical(this, QLatin1String("Error"),
                          QLatin1String("Selected directory is not a Git repository"));

}
<commit_msg>Fixes:    - tools->git->show commit dialog broken<commit_after>/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file.  Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.2, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/

#include "changeselectiondialog.h"

#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>

using namespace Git::Internal;

ChangeSelectionDialog::ChangeSelectionDialog(QWidget *parent)
    : QDialog(parent)
{
    m_ui.setupUi(this);
    connect(m_ui.repositoryButton, SIGNAL(clicked()), this, SLOT(selectWorkingDirectory()));
}

void ChangeSelectionDialog::selectWorkingDirectory()
{
    static QString location = QString();
    location = QFileDialog::getExistingDirectory(this,
                                      QLatin1String("Select Git repository"),
                                      location);
    if (location.isEmpty())
        return;

    // Verify that the location is a repository
    // We are polite, we also allow to specify a directory, which is not
    // the head directory of the repository.
    QDir repository(location);
    do {
        if (repository.entryList(QDir::AllDirs|QDir::Hidden).contains(QLatin1String(".git"))) {
            m_ui.repositoryEdit->setText(repository.absolutePath());
            return;
        }
    } while (repository.cdUp());

    // Did not find a repo
    QMessageBox::critical(this, QLatin1String("Error"),
                          QLatin1String("Selected directory is not a Git repository"));

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015-2018 dubalu.com LLC. All rights reserved.
 *
 * 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.
 */

#pragma once

#include <limits>             // for std::numeric_limits
#include <utility>            // for std::swap
#include <cstdlib>            // for std::strto*
#include <cstdio>             // for size_t
#include <sys/errno.h>        // for errno
#include <type_traits>        // for std::true_type, std::false_type

#include "exception.h"        // for InvalidArgument, OutOfRange
#include "string_view.h"      // for string_view

// Types conversion strict_stox and strict_nothrow_stox
template <typename F>
class Stox {
	const char * const name;
	F func;

	template <typename T, typename... Args>
	auto _stox(std::true_type, const string_view& str, std::size_t* idx, Args&&... args) noexcept {
		auto b = str.data();
		auto e = b + str.size();
		if (!b) {
			e = b = "";
		}
		auto ptr = const_cast<char*>(e);
		auto r = func(b, &ptr, std::forward<Args>(args)...);
		if (errno) return static_cast<decltype(r)>(0);
		if (ptr == b) {
			errno = EINVAL;
			return static_cast<decltype(r)>(0);
		}
		if (idx) {
			*idx = static_cast<size_t>(ptr - b);
		} else if (ptr != e) {
			errno = EINVAL;
			return static_cast<decltype(r)>(0);
		}
		return r;
	}

	template <typename T, typename... Args>
	auto _stox(std::false_type, const string_view& str, std::size_t* idx, Args&&... args) noexcept {
		auto r = _stox<void>(std::true_type{}, str, idx, std::forward<Args>(args)...);
		if (errno) return static_cast<T>(0);
		if (r < std::numeric_limits<T>::min() || std::numeric_limits<T>::max() < r) {
			errno = ERANGE;
			return static_cast<T>(0);
		}
		return static_cast<T>(r);
	}

public:
	Stox(const char* _name, F _func)
		: name(_name),
		  func(_func) { }

	template <typename T, typename... Args>
	auto stox_nothrow(int& errno_save, const string_view& str, std::size_t* idx, Args&&... args) {
		errno_save = errno;
		errno = 0;
		auto r = _stox<T>(std::is_same<void, T>{}, str, idx, std::forward<Args>(args)...);
		std::swap(errno, errno_save);
		return r;
	}

	template <typename T, typename... Args>
	auto stox_throw(const string_view& str, std::size_t* idx, Args&&... args) {
		auto errno_save = errno;
		errno = 0;
		auto r = _stox<T>(std::is_same<void, T>{}, str, idx, std::forward<Args>(args)...);
		std::swap(errno, errno_save);
		switch (errno) {
			case EINVAL:
				THROW(InvalidArgument, "%s: Cannot convert value: %s", name, std::string(str).c_str());
			case ERANGE:
				THROW(OutOfRange, "%s: Out of range value: %s", name, std::string(str).c_str());
			default:
				break;
		}
		return r;
	}
};
#define STOXIFY_BASE(name, func, T) \
static Stox<decltype(&func)> _strict_##name(#name, func); \
inline auto strict_##name(int& errno_save, string_view str, std::size_t* idx = nullptr, int base = 10) noexcept { \
	return _strict_##name.stox_nothrow<T>(errno_save, str, idx, base); \
} \
inline auto strict_##name(string_view str, std::size_t* idx = nullptr, int base = 10) { \
	return _strict_##name.stox_throw<T>(str, idx, base); \
}
#define STOXIFY(name, func, T) \
static Stox<decltype(&func)> _strict_##name(#name, func); \
inline auto strict_##name(int& errno_save, string_view str, std::size_t* idx = nullptr) noexcept { \
	return _strict_##name.stox_nothrow<T>(errno_save, str, idx); \
} \
inline auto strict_##name(string_view str, std::size_t* idx = nullptr) { \
	return _strict_##name.stox_throw<T>(str, idx); \
}
STOXIFY_BASE(stoul, std::strtoul, void);
STOXIFY_BASE(stoull, std::strtoull, void);
STOXIFY_BASE(stoi, std::strtol, int);
STOXIFY_BASE(stou, std::strtoul, unsigned);
STOXIFY_BASE(stol, std::strtol, void);
STOXIFY_BASE(stoll, std::strtoll, void);
STOXIFY_BASE(stoz, std::strtoull, std::size_t);
STOXIFY(stof, std::strtof, void);
STOXIFY(stod, std::strtod, void);
STOXIFY(stold, std::strtold, void);
#undef STOXIFY_BASE
#undef STOXIFY
<commit_msg>Using errno_save for validate stox operation<commit_after>/*
 * Copyright (C) 2015-2018 dubalu.com LLC. All rights reserved.
 *
 * 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.
 */

#pragma once

#include <limits>             // for std::numeric_limits
#include <utility>            // for std::swap
#include <cstdlib>            // for std::strto*
#include <cstdio>             // for size_t
#include <sys/errno.h>        // for errno
#include <type_traits>        // for std::true_type, std::false_type

#include "exception.h"        // for InvalidArgument, OutOfRange
#include "string_view.h"      // for string_view

// Types conversion strict_stox and strict_nothrow_stox
template <typename F>
class Stox {
	const char * const name;
	F func;

	template <typename T, typename... Args>
	auto _stox(std::true_type, const string_view& str, std::size_t* idx, Args&&... args) noexcept {
		auto b = str.data();
		auto e = b + str.size();
		if (!b) {
			e = b = "";
		}
		auto ptr = const_cast<char*>(e);
		auto r = func(b, &ptr, std::forward<Args>(args)...);
		if (errno) return static_cast<decltype(r)>(0);
		if (ptr == b) {
			errno = EINVAL;
			return static_cast<decltype(r)>(0);
		}
		if (idx) {
			*idx = static_cast<size_t>(ptr - b);
		} else if (ptr != e) {
			errno = EINVAL;
			return static_cast<decltype(r)>(0);
		}
		return r;
	}

	template <typename T, typename... Args>
	auto _stox(std::false_type, const string_view& str, std::size_t* idx, Args&&... args) noexcept {
		auto r = _stox<void>(std::true_type{}, str, idx, std::forward<Args>(args)...);
		if (errno) return static_cast<T>(0);
		if (r < std::numeric_limits<T>::min() || std::numeric_limits<T>::max() < r) {
			errno = ERANGE;
			return static_cast<T>(0);
		}
		return static_cast<T>(r);
	}

public:
	Stox(const char* _name, F _func)
		: name(_name),
		  func(_func) { }

	template <typename T, typename... Args>
	auto stox_nothrow(int& errno_save, const string_view& str, std::size_t* idx, Args&&... args) {
		errno_save = errno;
		errno = 0;
		auto r = _stox<T>(std::is_same<void, T>{}, str, idx, std::forward<Args>(args)...);
		std::swap(errno, errno_save);
		return r;
	}

	template <typename T, typename... Args>
	auto stox_throw(const string_view& str, std::size_t* idx, Args&&... args) {
		auto errno_save = errno;
		errno = 0;
		auto r = _stox<T>(std::is_same<void, T>{}, str, idx, std::forward<Args>(args)...);
		std::swap(errno, errno_save);
		switch (errno_save) {
			case EINVAL:
				THROW(InvalidArgument, "%s: Cannot convert value: %s", name, std::string(str).c_str());
			case ERANGE:
				THROW(OutOfRange, "%s: Out of range value: %s", name, std::string(str).c_str());
			default:
				break;
		}
		return r;
	}
};
#define STOXIFY_BASE(name, func, T) \
static Stox<decltype(&func)> _strict_##name(#name, func); \
inline auto strict_##name(int& errno_save, string_view str, std::size_t* idx = nullptr, int base = 10) noexcept { \
	return _strict_##name.stox_nothrow<T>(errno_save, str, idx, base); \
} \
inline auto strict_##name(string_view str, std::size_t* idx = nullptr, int base = 10) { \
	return _strict_##name.stox_throw<T>(str, idx, base); \
}
#define STOXIFY(name, func, T) \
static Stox<decltype(&func)> _strict_##name(#name, func); \
inline auto strict_##name(int& errno_save, string_view str, std::size_t* idx = nullptr) noexcept { \
	return _strict_##name.stox_nothrow<T>(errno_save, str, idx); \
} \
inline auto strict_##name(string_view str, std::size_t* idx = nullptr) { \
	return _strict_##name.stox_throw<T>(str, idx); \
}
STOXIFY_BASE(stoul, std::strtoul, void);
STOXIFY_BASE(stoull, std::strtoull, void);
STOXIFY_BASE(stoi, std::strtol, int);
STOXIFY_BASE(stou, std::strtoul, unsigned);
STOXIFY_BASE(stol, std::strtol, void);
STOXIFY_BASE(stoll, std::strtoll, void);
STOXIFY_BASE(stoz, std::strtoull, std::size_t);
STOXIFY(stof, std::strtof, void);
STOXIFY(stod, std::strtod, void);
STOXIFY(stold, std::strtold, void);
#undef STOXIFY_BASE
#undef STOXIFY
<|endoftext|>


<commit_before>/**
 * The Seeks proxy and plugin framework are part of the SEEKS project.
 * Copyright (C) 2010 Emmanuel Benazera, juban@free.fr
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "se_parser_yahoo.h"
#include "encode.h"
#include "miscutil.h"
#include "mem_utils.h"

#include <strings.h>
#include <iostream>

using sp::encode;
using sp::miscutil;

namespace seeks_plugins
{
   se_parser_yahoo::se_parser_yahoo()
     :_start_results(false),_begin_results(false),_title_flag(false),
      _summary_flag(false)
     {

     }

   se_parser_yahoo::~se_parser_yahoo()
     {

     }

   void se_parser_yahoo::start_element(parser_context *pc,
				       const xmlChar *name,
				       const xmlChar **attributes)
     {
	const char *tag = (const char*)name;

	if (strcasecmp(tag,"div") == 0)
	  {
	     const char *a_id = se_parser::get_attribute((const char**)attributes,"id");
	     const char *a_class = se_parser::get_attribute((const char**)attributes,"class");

	     if (!_start_results && a_id && strcasecmp(a_id,"web") == 0)
	       _start_results = true;
	     else if (_begin_results && a_class && strcasecmp(a_class,"abstr") == 0)
	       _summary_flag = true;
	     else if (_begin_results && a_class && strncasecmp(a_class,"res",3) == 0)
	       {
		  // create new snippet.
		  search_snippet *sp = new search_snippet(_count++);
		  sp->_engine |= std::bitset<NSEs>(SE_YAHOO);
		  pc->_current_snippet = sp;
		  pc->_snippets->push_back(pc->_current_snippet);
	       }
	  }
	else if (_start_results && strcasecmp(tag,"ol") == 0)
	  {
	     _begin_results = true;
	  }
	else if (_begin_results && strcasecmp(tag,"h3") == 0)
	  {
	     _title_flag = true;
	  }
	else if (strcasecmp(tag,"a") == 0)
	  {
	     const char *a_link = se_parser::get_attribute((const char**)attributes,"href");

	     if (a_link)
	       {
		  if (_title_flag && pc->_current_snippet)
		    {
		       std::string url_str = std::string(a_link);
		       size_t pos = 0;
		       if ((pos = url_str.find("rds.yahoo.com"))!=std::string::npos)
			 if ((pos = url_str.find("/**",pos))!=std::string::npos)
			   {
			      try
				{
				   url_str = url_str.substr(pos+3);
				}
			      catch(std::exception &e)
				{
				   // do nothing for now.
				}
			   }
		       const char *url_dec_str = encode::url_decode(url_str.c_str());
		       url_str = std::string(url_dec_str);
		       free_const(url_dec_str);
		       pc->_current_snippet->set_url(url_str);
		       pc->_current_snippet->set_cite(url_str);
		    }
		  else if (_begin_results && pc->_current_snippet)
		    pc->_current_snippet->_cached = std::string(a_link);
	       }
	  }
     }

   void se_parser_yahoo::characters(parser_context *pc,
				    const xmlChar *chars,
				    int length)
     {
	handle_characters(pc, chars, length);
     }

   void se_parser_yahoo::cdata(parser_context *pc,
			       const xmlChar *chars,
			       int length)
     {
	//handle_characters(pc, chars, length);
     }

   void se_parser_yahoo::handle_characters(parser_context *pc,
					   const xmlChar *chars,
					   int length)
     {
	if (_title_flag)
	  {
	     std::string a_chars = std::string((char*)chars);
	     miscutil::replace_in_string(a_chars,"\n"," ");
	     miscutil::replace_in_string(a_chars,"\r"," ");
	     _title += a_chars;
	  }
	else if (_summary_flag)
	  {
	     std::string a_chars = std::string((char*)chars);
	     miscutil::replace_in_string(a_chars,"\n"," ");
	     miscutil::replace_in_string(a_chars,"\r"," ");
	     miscutil::replace_in_string(a_chars,"-"," ");
	     _summary += a_chars;
	  }

     }

   void se_parser_yahoo::end_element(parser_context *pc,
				     const xmlChar *name)
     {
	const char *tag = (const char*)name;

	if (_begin_results && strcasecmp(tag,"ol") == 0)
	  {
	     _begin_results = false;
	  }
	else if (_title_flag && strcasecmp(tag,"h3") == 0)
	  {
	     _title_flag = false;
	     pc->_current_snippet->_title = _title;
	     _title = "";
	  }
	else if (_summary_flag && strcasecmp(tag,"div") == 0)
	  {
	     _summary_flag = false;
	     pc->_current_snippet->set_summary(_summary);
	     _summary = "";
	  }

     }

} /* end of namespace. */
<commit_msg>fixed missing summary in yahoo parser<commit_after>/**
 * The Seeks proxy and plugin framework are part of the SEEKS project.
 * Copyright (C) 2010 Emmanuel Benazera, juban@free.fr
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "se_parser_yahoo.h"
#include "encode.h"
#include "miscutil.h"
#include "mem_utils.h"

#include <strings.h>
#include <iostream>

using sp::encode;
using sp::miscutil;

namespace seeks_plugins
{
   se_parser_yahoo::se_parser_yahoo()
     :_start_results(false),_begin_results(false),_title_flag(false),
      _summary_flag(false)
     {

     }

   se_parser_yahoo::~se_parser_yahoo()
     {

     }

   void se_parser_yahoo::start_element(parser_context *pc,
				       const xmlChar *name,
				       const xmlChar **attributes)
     {
	const char *tag = (const char*)name;

	if (strcasecmp(tag,"div") == 0)
	  {
	     const char *a_id = se_parser::get_attribute((const char**)attributes,"id");
	     const char *a_class = se_parser::get_attribute((const char**)attributes,"class");

	     if (!_start_results && a_id && strcasecmp(a_id,"web") == 0)
	       _start_results = true;
	     else if (_begin_results && a_class && (strcasecmp(a_class,"abstr") == 0
						    || strcasecmp(a_class,"sm-abs") == 0))
	       _summary_flag = true;
	     else if (_begin_results && a_class && strncasecmp(a_class,"res",3) == 0)
	       {
		  // create new snippet.
		  search_snippet *sp = new search_snippet(_count++);
		  sp->_engine |= std::bitset<NSEs>(SE_YAHOO);
		  pc->_current_snippet = sp;
		  pc->_snippets->push_back(pc->_current_snippet);
	       }
	  }
	else if (_start_results && strcasecmp(tag,"ol") == 0)
	  {
	     _begin_results = true;
	  }
	else if (_begin_results && strcasecmp(tag,"h3") == 0)
	  {
	     _title_flag = true;
	  }
	else if (strcasecmp(tag,"a") == 0)
	  {
	     const char *a_link = se_parser::get_attribute((const char**)attributes,"href");

	     if (a_link)
	       {
		  if (_title_flag && pc->_current_snippet)
		    {
		       std::string url_str = std::string(a_link);
		       size_t pos = 0;
		       if ((pos = url_str.find("rds.yahoo.com"))!=std::string::npos)
			 if ((pos = url_str.find("/**",pos))!=std::string::npos)
			   {
			      try
				{
				   url_str = url_str.substr(pos+3);
				}
			      catch(std::exception &e)
				{
				   // do nothing for now.
				}
			   }
		       const char *url_dec_str = encode::url_decode(url_str.c_str());
		       url_str = std::string(url_dec_str);
		       free_const(url_dec_str);
		       pc->_current_snippet->set_url(url_str);
		       pc->_current_snippet->set_cite(url_str);
		    }
		  else if (_begin_results && pc->_current_snippet)
		    pc->_current_snippet->_cached = std::string(a_link);
	       }
	  }
     }

   void se_parser_yahoo::characters(parser_context *pc,
				    const xmlChar *chars,
				    int length)
     {
	handle_characters(pc, chars, length);
     }

   void se_parser_yahoo::cdata(parser_context *pc,
			       const xmlChar *chars,
			       int length)
     {
	//handle_characters(pc, chars, length);
     }

   void se_parser_yahoo::handle_characters(parser_context *pc,
					   const xmlChar *chars,
					   int length)
     {
	if (_title_flag)
	  {
	     std::string a_chars = std::string((char*)chars);
	     miscutil::replace_in_string(a_chars,"\n"," ");
	     miscutil::replace_in_string(a_chars,"\r"," ");
	     _title += a_chars;
	  }
	else if (_summary_flag)
	  {
	     std::string a_chars = std::string((char*)chars);
	     miscutil::replace_in_string(a_chars,"\n"," ");
	     miscutil::replace_in_string(a_chars,"\r"," ");
	     miscutil::replace_in_string(a_chars,"-"," ");
	     _summary += a_chars;
	  }

     }

   void se_parser_yahoo::end_element(parser_context *pc,
				     const xmlChar *name)
     {
	const char *tag = (const char*)name;

	if (_begin_results && strcasecmp(tag,"ol") == 0)
	  {
	     _begin_results = false;
	  }
	else if (_title_flag && strcasecmp(tag,"h3") == 0)
	  {
	     _title_flag = false;
	     pc->_current_snippet->_title = _title;
	     _title = "";
	  }
	else if (_summary_flag && strcasecmp(tag,"div") == 0)
	  {
	     _summary_flag = false;
	     pc->_current_snippet->set_summary(_summary);
	     _summary = "";
	  }

     }

} /* end of namespace. */
<|endoftext|>


<commit_before>/*
Copyright (c) 2017 InversePalindrome
Memento Mori - CombatSystem.cpp
InversePalindrome.com
*/

#include "CombatSystem.hpp"
#include "EntityManager.hpp"
#include "SystemManager.hpp"
#include "StateComponent.hpp"
#include "HealthComponent.hpp"
#include "PositionComponent.hpp"
#include "VelocityComponent.hpp"
#include "StateSystem.hpp"

CombatSystem::CombatSystem(SystemManager& systemManager) :
	System(System::ID::Combat, systemManager)
{
	EntityComposition entityComposition;

	entityComposition[static_cast<std::size_t>(Component::ID::Attack)] = true;
	entityComposition[static_cast<std::size_t>(Component::ID::Position)] = true;
	entityComposition[static_cast<std::size_t>(Component::ID::Velocity)] = true;
	entityComposition[static_cast<std::size_t>(Component::ID::State)] = true;

	componentRequirements.push_back(entityComposition);

	entityComposition[static_cast<std::size_t>(Component::ID::Health)] = true;

	componentRequirements.push_back(entityComposition);

	systemManager.getMessageHandler()->subscribe(EntityMessage::ReadyToAttack, this);
	systemManager.getMessageHandler()->subscribe(EntityMessage::StateChanged, this);
	systemManager.getMessageHandler()->subscribe(EntityMessage::PickedUpHeart, this);
}

void CombatSystem::handleEvent(EntityID entityID, EntityEvent event)
{
	if (this->hasEntity(entityID))
	{
		switch (event)
		{
		case EntityEvent::ShootProjectile:
			this->shootProjectile(entityID);
			break;
		}
	}
}

void CombatSystem::update(sf::Time deltaTime)
{
	for (auto& entity : this->entitiesIDs)
	{
		auto* attack = this->systemManager->getEntityManager()->getComponent<AttackComponent>(entity, Component::ID::Attack);
		auto position = this->systemManager->getEntityManager()->getComponent<PositionComponent>(entity, Component::ID::Position)->getPosition();
		auto direction = this->systemManager->getEntityManager()->getComponent<VelocityComponent>(entity, Component::ID::Velocity)->getDirection();

		attack->setPosition(position);
		attack->setAttackDirection(direction);
	}
}

void CombatSystem::notify(const Message& message)
{
	switch (message.messageType)
	{
	case EntityMessage::ReadyToAttack:
		if (this->hasEntity(message.senderID))
		{
			this->processAttack(message.senderID, message.receiverID);
		}
	    break;

	case EntityMessage::StateChanged:
		if (this->hasEntity(message.receiverID))
		{
			auto* attack = this->systemManager->getEntityManager()->getComponent<AttackComponent>(message.receiverID, Component::ID::Attack);

			attack->setAttackStatus(false);
		}
		break;

	case EntityMessage::PickedUpHeart:
		if (this->hasEntity(message.receiverID))
		{
			this->processHeartPickup(message.senderID, message.receiverID);
		}
		break;
	}
}

void CombatSystem::processAttack(EntityID senderID, EntityID receiverID)
{
	auto* attack = this->systemManager->getEntityManager()->getComponent<AttackComponent>(senderID, Component::ID::Attack);
	auto* state1 = this->systemManager->getEntityManager()->getComponent<StateComponent>(senderID, Component::ID::State);
	auto* health = this->systemManager->getEntityManager()->getComponent<HealthComponent>(receiverID, Component::ID::Health);

	if (state1->getState() != EntityState::Attacking || attack->hasAttacked() || !health)
	{
		return;
	}

	if (attack->isProjectile())
	{
		auto* state2 = this->systemManager->getEntityManager()->getComponent<StateComponent>(senderID, Component::ID::State);

		state2->setState(EntityState::Dead);
		this->systemManager->addEvent(senderID, EntityEvent::ReachedTarget);
	}

	health->setHealth(health->getHealth() - 1);
	attack->setAttackStatus(true);

	if (!health->getHealth())
	{
		auto* state2 = this->systemManager->getEntityManager()->getComponent<StateComponent>(receiverID, Component::ID::State);

		state2->setState(EntityState::Dead);
		this->systemManager->addEvent(receiverID, EntityEvent::Died);
	}

	this->applyKnockback(receiverID, attack);
}

void CombatSystem::processHeartPickup(EntityID senderID, EntityID receiverID)
{
	auto* health = this->systemManager->getEntityManager()->getComponent<HealthComponent>(receiverID, Component::ID::Health);

	if (health)
	{
		health->setHealth(health->getHealth() + 1u);
	}

	this->systemManager->getEntityManager()->removeEntity(senderID);
}

void CombatSystem::applyKnockback(EntityID entityID, AttackComponent* attack)
{
	auto* velocity = this->systemManager->getEntityManager()->getComponent<VelocityComponent>(entityID, Component::ID::Velocity);

	if (attack->getAttackDirection() == Direction::Up)
	{
		velocity->setVelocity(sf::Vector2f(0.f, -attack->getKnockback()));
	}
	else if (attack->getAttackDirection() == Direction::Down)
	{
		velocity->setVelocity(sf::Vector2f(0.f, attack->getKnockback()));
	}
	else if (attack->getAttackDirection() == Direction::Right)
	{
		velocity->setVelocity(sf::Vector2f(attack->getKnockback(), 0.f));
	}
	else
	{
		velocity->setVelocity(sf::Vector2f(-attack->getKnockback(), 0.f));
	}
}

void CombatSystem::shootProjectile(EntityID entityID)
{
	this->systemManager->getEntityManager()->addEntity("Resources/Files/Fireball.txt");

	auto entityDirection = this->systemManager->getEntityManager()->getComponent<VelocityComponent>
		(entityID, Component::ID::Velocity)->getDirection();

	auto entityPosition = this->systemManager->getEntityManager()->getComponent<PositionComponent>(entityID, Component::ID::Position)->getPosition();

	auto* projectileDirection = this->systemManager->getEntityManager()->getComponent<VelocityComponent>
		(this->systemManager->getEntityManager()->getCurrentEntityID() - 1u, Component::ID::Velocity);

	auto* projectilePosition = this->systemManager->getEntityManager()->getComponent<PositionComponent>
		(this->systemManager->getEntityManager()->getCurrentEntityID() - 1u, Component::ID::Position);

	const float xProjectileOffset = 100.f;
	const float yProjectileOffset = 140.f;

	Message message(EntityMessage::DirectionChanged);
	message.receiverID = this->systemManager->getEntityManager()->getCurrentEntityID() - 1u;

	switch (entityDirection)
	{
	case Direction::Up:
		projectilePosition->setPosition(entityPosition - sf::Vector2f(0.f, yProjectileOffset));
		projectileDirection->setDirection(Direction::Down);

		message.data[DataID::Direction] = static_cast<std::size_t>(Direction::Up);
		break;
	case Direction::Down:
		projectilePosition->setPosition(entityPosition + sf::Vector2f(0.f, yProjectileOffset));
		projectileDirection->setDirection(Direction::Up);

		message.data[DataID::Direction] = static_cast<std::size_t>(Direction::Down);
		break;
	case Direction::Right:
		projectilePosition->setPosition(entityPosition + sf::Vector2f(xProjectileOffset, 0.f));
		projectileDirection->setDirection(Direction::Left);

		message.data[DataID::Direction] = static_cast<std::size_t>(Direction::Right);
		break;
	case Direction::Left:
		projectilePosition->setPosition(entityPosition - sf::Vector2f(xProjectileOffset, 0.f));
		projectileDirection->setDirection(Direction::Right);

		message.data[DataID::Direction] = static_cast<std::size_t>(Direction::Left);
		break;
	}

	this->systemManager->getMessageHandler()->dispatch(message);
}<commit_msg>Delete CombatSystem.cpp<commit_after><|endoftext|>