<commit_before>/* Definition of the pqxx::stream_from class.
 *
 * pqxx::stream_from enables optimized batch reads from a database table.
 *
 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stream_from instead.
 *
 * Copyright (c) 2000-2020, Jeroen T. Vermeulen.
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this
 * mistake, or contact the author.
 */
#ifndef PQXX_H_STREAM_FROM
#define PQXX_H_STREAM_FROM

#include "pqxx/compiler-public.hxx"
#include "pqxx/internal/compiler-internal-pre.hxx"

#include <cassert>
#include <functional>
#include <variant>

#include "pqxx/except.hxx"
#include "pqxx/internal/encoding_group.hxx"
#include "pqxx/internal/stream_iterator.hxx"
#include "pqxx/internal/transaction_focus.hxx"
#include "pqxx/separated_list.hxx"
#include "pqxx/transaction_base.hxx"

namespace pqxx
{
/// Pass this to a @c stream_from constructor to stream table contents.
constexpr from_table_t from_table;
/// Pass this to a @c stream_from constructor to stream query results.
constexpr from_query_t from_query;

/// Stream data from the database.
/** Retrieving data this way is likely to be faster than executing a query and
 * then iterating and converting the rows fields.  You will also be able to
 * start processing before all of the data has come in.
 *
 * There are also downsides.  If there's an error, it may leave the entire
 * connection in an unusable state, so you'll have to give the whole thing up.
 * Also, your connection to the database may break before you've received all
 * the data, so you may end up processing only part of the data.  Finally,
 * opening a stream puts the connection in a special state, so you won't be
 * able to do many other things with the connection or the transaction while
 * the stream is open.
 *
 * There are two ways of starting a stream: you stream either all rows in a
 * table (in which case, use a constructor which accepts @c pqxx::from_table),
 * or the results of a query (in which case, use a concstructor which accepts
 * @c pqxx::from_query).
 *
 * Usually you'll want the @c stream convenience wrapper in transaction_base,
 * so you don't need to deal with this class directly.
 */
class PQXX_LIBEXPORT stream_from : internal::transactionfocus
{
public:
  using raw_line =
    std::pair<std::unique_ptr<char, std::function<void(char *)>>, std::size_t>;

  /// Execute query, and stream over the results.
  /** The query can be a SELECT query or a VALUES query; or it can be an
   * UPDATE, INSERT, or DELETE with a RETURNING clause.
   *
   * The query is executed as part of a COPY statement, so there are additional
   * restrictions on what kind of query you can use here.  See the PostgreSQL
   * documentation for the COPY command:
   *
   *     https://www.postgresql.org/docs/current/sql-copy.html
   */
  stream_from(transaction_base &, from_query_t, std::string_view query);

  /// Stream all rows in table, all columns.
  stream_from(transaction_base &, from_table_t, std::string_view table);

  /// Stream given columns from all rows in table.
  template<typename Iter>
  stream_from(
    transaction_base &, from_table_t, std::string_view table,
    Iter columns_begin, Iter columns_end);

  /// Stream given columns from all rows in table.
  template<typename Columns>
  stream_from(
    transaction_base &tx, from_table_t, std::string_view table,
    Columns const &columns);

  /// @deprecated Use the @c from_table_t overload instead.
  stream_from(transaction_base &tx, std::string_view table) :
          stream_from{tx, from_table, table}
  {}

  /// @deprecated Use the @c from_table_t overload instead.
  template<typename Columns>
  stream_from(
    transaction_base &tx, std::string_view table, Columns const &columns) :
          stream_from{tx, from_table, table, columns}
  {}

  /// @deprecated Use the @c from_table_t overload instead.
  template<typename Iter>
  stream_from(
    transaction_base &, std::string_view table, Iter columns_begin,
    Iter columns_end);

  ~stream_from() noexcept;

  [[nodiscard]] operator bool() const noexcept { return not m_finished; }
  [[nodiscard]] bool operator!() const noexcept { return m_finished; }

  /// Finish this stream.  Call this before continuing to use the connection.
  /** Consumes all remaining lines, and closes the stream.
   *
   * This may take a while if you're abandoning the stream before it's done, so
   * skip it in error scenarios where you're not planning to use the connection
   * again afterwards.
   */
  void complete();

  /// Read one row into a tuple.
  /** Converts the row's fields into the fields making up the tuple.
   *
   * For a column which can contain nulls, be sure to give the corresponding
   * tuple field a type which can be null.  For example, to read a field as
   * @c int when it may contain nulls, read it as @c std::optional<int>.
   * Using @c std::shared_ptr or @c std::unique_ptr will also work.
   */
  raw_line get_raw_line();
  template<typename Tuple> stream_from &operator>>(Tuple &);

  /// Doing this with a @c std::variant is going to be horrifically borked.
  template<typename... Vs>
  stream_from &operator>>(std::variant<Vs...> &) = delete;

  /// Iterate over this stream.  Supports range-based "for" loops.
  /** Produces an input iterator over the stream.
   *
   * Do not call this yourself.  Use it like "for (auto data : stream.iter())".
   */
  template<typename... TYPE>[[nodiscard]] auto iter()
  {
    return pqxx::internal::stream_input_iteration<TYPE...>{*this};
  }

private:
  stream_from(
    transaction_base &tx, std::string_view table, std::string &&columns,
    from_table_t);

  // XXX: Can we make template args implicit?
  template<typename Tuple, std::size_t... indexes>
  void extract_fields(Tuple &t, std::index_sequence<indexes...>) const
  {
    (extract_value<Tuple, indexes>(t), ...);
  }

  static std::string compose_query(
    transaction_base const &tx, std::string_view table,
    std::string const &columns);

  pqxx::internal::glyph_scanner_func *m_glyph_scanner;

  /// Current row's fields' text, combined into one reusable string.
  std::string m_row;

  /// The current row's fields.
  std::vector<zview> m_fields;

  bool m_finished = false;

  void close();

  template<typename Tuple, std::size_t index>
  void extract_value(Tuple &) const;

  /// Read a line of COPY data, write @c m_row and @c m_fields.
  void parse_line();
};

template<typename Columns>
inline stream_from::stream_from(
  transaction_base &tb, from_table_t, std::string_view table_name,
  Columns const &columns) :
        stream_from{tb, from_table, table_name, std::begin(columns),
                    std::end(columns)}
{}

template<typename Iter>
inline stream_from::stream_from(
  transaction_base &tx, from_table_t, std::string_view table,
  Iter columns_begin, Iter columns_end) :
        stream_from{tx, table, separated_list(",", columns_begin, columns_end),
                    from_table}
{}

template<typename Tuple> inline stream_from &stream_from::operator>>(Tuple &t)
{
  if (m_finished)
    return *this;
  constexpr auto tup_size{std::tuple_size_v<Tuple>};
  m_fields.reserve(tup_size);
  parse_line();
  if (m_finished)
    return *this;

  if (m_fields.size() != tup_size)
    throw usage_error{"Tried to extract " + to_string(tup_size) +
                      " field(s) from a stream of " +
                      to_string(m_fields.size()) + "."};

  extract_fields(t, std::make_index_sequence<tup_size>{});
  return *this;
}

template<typename Tuple, std::size_t index>
inline void stream_from::extract_value(Tuple &t) const
{
  using field_type = std::remove_reference_t<decltype(std::get<index>(t))>;
  assert(index < m_fields.size());
  if constexpr (std::is_same_v<field_type, std::nullptr_t>)
  {
    if (m_fields[index].data() != nullptr)
      throw conversion_error{"Streaming non-null value into nullptr_t field."};
  }
  else if (m_fields[index].data() == nullptr)
  {
    if constexpr (nullness<field_type>::has_null)
      std::get<index>(t) = nullness<field_type>::null();
    else
      internal::throw_null_conversion(type_name<field_type>);
  }
  else
  {
    // Don't ever try to convert a non-null value to nullptr_t!
    std::get<index>(t) = from_string<field_type>(m_fields[index]);
  }
}
} // namespace pqxx

#include "pqxx/internal/compiler-internal-post.hxx"
#endif
<commit_msg>Generalise a `nullptr_t` to `always_null`.<commit_after>/* Definition of the pqxx::stream_from class.
 *
 * pqxx::stream_from enables optimized batch reads from a database table.
 *
 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stream_from instead.
 *
 * Copyright (c) 2000-2020, Jeroen T. Vermeulen.
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this
 * mistake, or contact the author.
 */
#ifndef PQXX_H_STREAM_FROM
#define PQXX_H_STREAM_FROM

#include "pqxx/compiler-public.hxx"
#include "pqxx/internal/compiler-internal-pre.hxx"

#include <cassert>
#include <functional>
#include <variant>

#include "pqxx/except.hxx"
#include "pqxx/internal/encoding_group.hxx"
#include "pqxx/internal/stream_iterator.hxx"
#include "pqxx/internal/transaction_focus.hxx"
#include "pqxx/separated_list.hxx"
#include "pqxx/transaction_base.hxx"

namespace pqxx
{
/// Pass this to a @c stream_from constructor to stream table contents.
constexpr from_table_t from_table;
/// Pass this to a @c stream_from constructor to stream query results.
constexpr from_query_t from_query;

/// Stream data from the database.
/** Retrieving data this way is likely to be faster than executing a query and
 * then iterating and converting the rows fields.  You will also be able to
 * start processing before all of the data has come in.
 *
 * There are also downsides.  If there's an error, it may leave the entire
 * connection in an unusable state, so you'll have to give the whole thing up.
 * Also, your connection to the database may break before you've received all
 * the data, so you may end up processing only part of the data.  Finally,
 * opening a stream puts the connection in a special state, so you won't be
 * able to do many other things with the connection or the transaction while
 * the stream is open.
 *
 * There are two ways of starting a stream: you stream either all rows in a
 * table (in which case, use a constructor which accepts @c pqxx::from_table),
 * or the results of a query (in which case, use a concstructor which accepts
 * @c pqxx::from_query).
 *
 * Usually you'll want the @c stream convenience wrapper in transaction_base,
 * so you don't need to deal with this class directly.
 */
class PQXX_LIBEXPORT stream_from : internal::transactionfocus
{
public:
  using raw_line =
    std::pair<std::unique_ptr<char, std::function<void(char *)>>, std::size_t>;

  /// Execute query, and stream over the results.
  /** The query can be a SELECT query or a VALUES query; or it can be an
   * UPDATE, INSERT, or DELETE with a RETURNING clause.
   *
   * The query is executed as part of a COPY statement, so there are additional
   * restrictions on what kind of query you can use here.  See the PostgreSQL
   * documentation for the COPY command:
   *
   *     https://www.postgresql.org/docs/current/sql-copy.html
   */
  stream_from(transaction_base &, from_query_t, std::string_view query);

  /// Stream all rows in table, all columns.
  stream_from(transaction_base &, from_table_t, std::string_view table);

  /// Stream given columns from all rows in table.
  template<typename Iter>
  stream_from(
    transaction_base &, from_table_t, std::string_view table,
    Iter columns_begin, Iter columns_end);

  /// Stream given columns from all rows in table.
  template<typename Columns>
  stream_from(
    transaction_base &tx, from_table_t, std::string_view table,
    Columns const &columns);

  /// @deprecated Use the @c from_table_t overload instead.
  stream_from(transaction_base &tx, std::string_view table) :
          stream_from{tx, from_table, table}
  {}

  /// @deprecated Use the @c from_table_t overload instead.
  template<typename Columns>
  stream_from(
    transaction_base &tx, std::string_view table, Columns const &columns) :
          stream_from{tx, from_table, table, columns}
  {}

  /// @deprecated Use the @c from_table_t overload instead.
  template<typename Iter>
  stream_from(
    transaction_base &, std::string_view table, Iter columns_begin,
    Iter columns_end);

  ~stream_from() noexcept;

  [[nodiscard]] operator bool() const noexcept { return not m_finished; }
  [[nodiscard]] bool operator!() const noexcept { return m_finished; }

  /// Finish this stream.  Call this before continuing to use the connection.
  /** Consumes all remaining lines, and closes the stream.
   *
   * This may take a while if you're abandoning the stream before it's done, so
   * skip it in error scenarios where you're not planning to use the connection
   * again afterwards.
   */
  void complete();

  /// Read one row into a tuple.
  /** Converts the row's fields into the fields making up the tuple.
   *
   * For a column which can contain nulls, be sure to give the corresponding
   * tuple field a type which can be null.  For example, to read a field as
   * @c int when it may contain nulls, read it as @c std::optional<int>.
   * Using @c std::shared_ptr or @c std::unique_ptr will also work.
   */
  raw_line get_raw_line();
  template<typename Tuple> stream_from &operator>>(Tuple &);

  /// Doing this with a @c std::variant is going to be horrifically borked.
  template<typename... Vs>
  stream_from &operator>>(std::variant<Vs...> &) = delete;

  /// Iterate over this stream.  Supports range-based "for" loops.
  /** Produces an input iterator over the stream.
   *
   * Do not call this yourself.  Use it like "for (auto data : stream.iter())".
   */
  template<typename... TYPE>[[nodiscard]] auto iter()
  {
    return pqxx::internal::stream_input_iteration<TYPE...>{*this};
  }

private:
  stream_from(
    transaction_base &tx, std::string_view table, std::string &&columns,
    from_table_t);

  // XXX: Can we make template args implicit?
  template<typename Tuple, std::size_t... indexes>
  void extract_fields(Tuple &t, std::index_sequence<indexes...>) const
  {
    (extract_value<Tuple, indexes>(t), ...);
  }

  static std::string compose_query(
    transaction_base const &tx, std::string_view table,
    std::string const &columns);

  pqxx::internal::glyph_scanner_func *m_glyph_scanner;

  /// Current row's fields' text, combined into one reusable string.
  std::string m_row;

  /// The current row's fields.
  std::vector<zview> m_fields;

  bool m_finished = false;

  void close();

  template<typename Tuple, std::size_t index>
  void extract_value(Tuple &) const;

  /// Read a line of COPY data, write @c m_row and @c m_fields.
  void parse_line();
};

template<typename Columns>
inline stream_from::stream_from(
  transaction_base &tb, from_table_t, std::string_view table_name,
  Columns const &columns) :
        stream_from{tb, from_table, table_name, std::begin(columns),
                    std::end(columns)}
{}

template<typename Iter>
inline stream_from::stream_from(
  transaction_base &tx, from_table_t, std::string_view table,
  Iter columns_begin, Iter columns_end) :
        stream_from{tx, table, separated_list(",", columns_begin, columns_end),
                    from_table}
{}

template<typename Tuple> inline stream_from &stream_from::operator>>(Tuple &t)
{
  if (m_finished)
    return *this;
  constexpr auto tup_size{std::tuple_size_v<Tuple>};
  m_fields.reserve(tup_size);
  parse_line();
  if (m_finished)
    return *this;

  if (m_fields.size() != tup_size)
    throw usage_error{"Tried to extract " + to_string(tup_size) +
                      " field(s) from a stream of " +
                      to_string(m_fields.size()) + "."};

  extract_fields(t, std::make_index_sequence<tup_size>{});
  return *this;
}

template<typename Tuple, std::size_t index>
inline void stream_from::extract_value(Tuple &t) const
{
  using field_type = std::remove_reference_t<decltype(std::get<index>(t))>;
  assert(index < m_fields.size());
  if constexpr (nullness<field_type>::always_null)
  {
    if (m_fields[index].data() != nullptr)
      throw conversion_error{"Streaming non-null value into null field."};
  }
  else if (m_fields[index].data() == nullptr)
  {
    if constexpr (nullness<field_type>::has_null)
      std::get<index>(t) = nullness<field_type>::null();
    else
      internal::throw_null_conversion(type_name<field_type>);
  }
  else
  {
    // Don't ever try to convert a non-null value to nullptr_t!
    std::get<index>(t) = from_string<field_type>(m_fields[index]);
  }
}
} // namespace pqxx

#include "pqxx/internal/compiler-internal-post.hxx"
#endif
<|endoftext|>


<commit_before>/***************************************************************************
* Copyright (c) 2017, Sylvain Corlay and Johan Mabille                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XWIDGETS_SLIDER_HPP
#define XWIDGETS_SLIDER_HPP

#include <string>

#include "xtl/xoptional.hpp"

#include "xcolor.hpp"
#include "xeither.hpp"
#include "xmaterialize.hpp"
#include "xnumber.hpp"
#include "xstyle.hpp"

namespace xw
{
    /****************************
     * slider_style declaration *
     ****************************/

    template <class D>
    class xslider_style : public xstyle<D>
    {
    public:

        using base_type = xstyle<D>;
        using derived_type = D;

        xeus::xjson get_state() const;
        void apply_patch(const xeus::xjson&);

        XPROPERTY(std::string, derived_type, description_width);
        XPROPERTY(xtl::xoptional<html_color>, derived_type, handle_color);

    protected:

        xslider_style();
        using base_type::base_type;

    private:

        void set_defaults();
    };

    using slider_style = xmaterialize<xslider_style>;

    using slider_style_generator = xgenerator<xslider_style>;

    /**********************
     * slider declaration *
     **********************/

    template <class D>
    class xslider : public xnumber<D>
    {
    public:

        using base_type = xnumber<D>;
        using derived_type = D;

        using value_type = typename base_type::value_type;

        xeus::xjson get_state() const;
        void apply_patch(const xeus::xjson&);

        XPROPERTY(value_type, derived_type, step, value_type(1));
        XPROPERTY(std::string, derived_type, orientation, "horizontal", XEITHER("horizontal", "vertical"));
        XPROPERTY(bool, derived_type, readout, true);
        XPROPERTY(std::string, derived_type, readout_format, ".2f");
        XPROPERTY(bool, derived_type, continuous_update, true);
        XPROPERTY(bool, derived_type, disabled);
        XPROPERTY(::xw::slider_style, derived_type, style);

    protected:

        xslider();
        using base_type::base_type;

    private:

        void set_defaults();
    };

    template <class T>
    using slider = xmaterialize<xslider, T>;

    template <class T>
    using slider_generator = xgenerator<xslider, T>;

    template <class T>
    struct xnumber_traits<slider<T>>
    {
        using value_type = T;
    };

    template <class T>
    struct xnumber_traits<slider_generator<T>>
    {
        using value_type = T;
    };

    /********************************
     * xslider_style implementation *
     ********************************/

    template <class D>
    inline xeus::xjson xslider_style<D>::get_state() const
    {
        xeus::xjson state = base_type::get_state();

        XOBJECT_SET_PATCH_FROM_PROPERTY(description_width, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(handle_color, state);

        return state;
    }

    template <class D>
    inline void xslider_style<D>::apply_patch(const xeus::xjson& patch)
    {
        base_type::apply_patch(patch);

        XOBJECT_SET_PROPERTY_FROM_PATCH(description_width, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(handle_color, patch);
    }

    template <class D>
    inline xslider_style<D>::xslider_style()
        : base_type()
    {
        set_defaults();
    }

    template <class D>
    inline void xslider_style<D>::set_defaults()
    {
        this->_model_module() = "@jupyter-widgets/controls";
        this->_model_name() = "SliderStyleModel";
    }

    /**************************
     * xslider implementation *
     **************************/

    template <class D>
    inline xeus::xjson xslider<D>::get_state() const
    {
        xeus::xjson state = base_type::get_state();

        XOBJECT_SET_PATCH_FROM_PROPERTY(step, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(orientation, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(readout, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(readout_format, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(continuous_update, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(disabled, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(style, state);

        return state;
    }

    template <class D>
    inline void xslider<D>::apply_patch(const xeus::xjson& patch)
    {
        base_type::apply_patch(patch);

        XOBJECT_SET_PROPERTY_FROM_PATCH(step, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(orientation, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(readout, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(readout_format, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(continuous_update, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(disabled, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(style, patch);
    }

    template <class D>
    inline xslider<D>::xslider()
        : base_type()
    {
        set_defaults();

        this->template validate<decltype(this->value)>([this](auto& proposal) {
            if (proposal > this->max())
            {
                proposal = this->max();
            }
            if (proposal < this->min())
            {
                proposal = this->min();
            }
        });

        this->template validate<decltype(this->min)>([this](auto& proposal) {
            if (proposal > this->max())
            {
                throw std::runtime_error("setting min > max");
            }
            if (proposal > this->value())
            {
                this->value = proposal;
            }
        });

        this->template validate<decltype(this->max)>([this](auto& proposal) {
            if (proposal < this->min())
            {
                throw std::runtime_error("setting max < min");
            }
            if (proposal < this->value())
            {
                this->value = proposal;
            }
        });
    }

    template <class D>
    inline void xslider<D>::set_defaults()
    {
        this->_model_name() = "FloatSliderModel";
        this->_view_name() = "FloatSliderView";
    }
}

#endif
<commit_msg>separate setup-properties in slider constructor<commit_after>/***************************************************************************
* Copyright (c) 2017, Sylvain Corlay and Johan Mabille                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XWIDGETS_SLIDER_HPP
#define XWIDGETS_SLIDER_HPP

#include <string>

#include "xtl/xoptional.hpp"

#include "xcolor.hpp"
#include "xeither.hpp"
#include "xmaterialize.hpp"
#include "xnumber.hpp"
#include "xstyle.hpp"

namespace xw
{
    /****************************
     * slider_style declaration *
     ****************************/

    template <class D>
    class xslider_style : public xstyle<D>
    {
    public:

        using base_type = xstyle<D>;
        using derived_type = D;

        xeus::xjson get_state() const;
        void apply_patch(const xeus::xjson&);

        XPROPERTY(std::string, derived_type, description_width);
        XPROPERTY(xtl::xoptional<html_color>, derived_type, handle_color);

    protected:

        xslider_style();
        using base_type::base_type;

    private:

        void set_defaults();
    };

    using slider_style = xmaterialize<xslider_style>;

    using slider_style_generator = xgenerator<xslider_style>;

    /**********************
     * slider declaration *
     **********************/

    template <class D>
    class xslider : public xnumber<D>
    {
    public:

        using base_type = xnumber<D>;
        using derived_type = D;

        using value_type = typename base_type::value_type;

        xeus::xjson get_state() const;
        void apply_patch(const xeus::xjson&);

        XPROPERTY(value_type, derived_type, step, value_type(1));
        XPROPERTY(std::string, derived_type, orientation, "horizontal", XEITHER("horizontal", "vertical"));
        XPROPERTY(bool, derived_type, readout, true);
        XPROPERTY(std::string, derived_type, readout_format, ".2f");
        XPROPERTY(bool, derived_type, continuous_update, true);
        XPROPERTY(bool, derived_type, disabled);
        XPROPERTY(::xw::slider_style, derived_type, style);

    protected:

        xslider();
        using base_type::base_type;

    private:

        void set_defaults();

        void setup_properties();
    };

    template <class T>
    using slider = xmaterialize<xslider, T>;

    template <class T>
    using slider_generator = xgenerator<xslider, T>;

    template <class T>
    struct xnumber_traits<slider<T>>
    {
        using value_type = T;
    };

    template <class T>
    struct xnumber_traits<slider_generator<T>>
    {
        using value_type = T;
    };

    /********************************
     * xslider_style implementation *
     ********************************/

    template <class D>
    inline xeus::xjson xslider_style<D>::get_state() const
    {
        xeus::xjson state = base_type::get_state();

        XOBJECT_SET_PATCH_FROM_PROPERTY(description_width, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(handle_color, state);

        return state;
    }

    template <class D>
    inline void xslider_style<D>::apply_patch(const xeus::xjson& patch)
    {
        base_type::apply_patch(patch);

        XOBJECT_SET_PROPERTY_FROM_PATCH(description_width, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(handle_color, patch);
    }

    template <class D>
    inline xslider_style<D>::xslider_style()
        : base_type()
    {
        set_defaults();
    }

    template <class D>
    inline void xslider_style<D>::set_defaults()
    {
        this->_model_module() = "@jupyter-widgets/controls";
        this->_model_name() = "SliderStyleModel";
    }

    /**************************
     * xslider implementation *
     **************************/

    template <class D>
    inline xeus::xjson xslider<D>::get_state() const
    {
        xeus::xjson state = base_type::get_state();

        XOBJECT_SET_PATCH_FROM_PROPERTY(step, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(orientation, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(readout, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(readout_format, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(continuous_update, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(disabled, state);
        XOBJECT_SET_PATCH_FROM_PROPERTY(style, state);

        return state;
    }

    template <class D>
    inline void xslider<D>::apply_patch(const xeus::xjson& patch)
    {
        base_type::apply_patch(patch);

        XOBJECT_SET_PROPERTY_FROM_PATCH(step, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(orientation, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(readout, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(readout_format, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(continuous_update, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(disabled, patch);
        XOBJECT_SET_PROPERTY_FROM_PATCH(style, patch);
    }

    template <class D>
    inline xslider<D>::xslider()
        : base_type()
    {
        set_defaults();

        this->setup_properties();
    }

    template <class D>
    inline void xslider<D>::setup_properties()
    {
        this->template validate<decltype(this->value)>([this](auto& proposal) {
            if (proposal > this->max())
            {
                proposal = this->max();
            }
            if (proposal < this->min())
            {
                proposal = this->min();
            }
        });

        this->template validate<decltype(this->min)>([this](auto& proposal) {
            if (proposal > this->max())
            {
                throw std::runtime_error("setting min > max");
            }
            if (proposal > this->value())
            {
                this->value = proposal;
            }
        });

        this->template validate<decltype(this->max)>([this](auto& proposal) {
            if (proposal < this->min())
            {
                throw std::runtime_error("setting max < min");
            }
            if (proposal < this->value())
            {
                this->value = proposal;
            }
        });
    }

    template <class D>
    inline void xslider<D>::set_defaults()
    {
        this->_model_name() = "FloatSliderModel";
        this->_view_name() = "FloatSliderView";
    }
}

#endif
<|endoftext|>


<commit_before>// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
// Color.cc for Blackbox - an X11 Window manager
// Copyright (c) 2001 - 2005 Sean 'Shaleh' Perry <shaleh at debian.org>
// Copyright (c) 1997 - 2000, 2002 - 2005
//         Bradley T Hughes <bhughes at trolltech.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#include "Color.hh"
#include "Display.hh"

#include <map>

#include <X11/Xlib.h>

#include <assert.h>
#include <stdio.h>

// #define COLORCACHE_DEBUG

namespace bt {

  class ColorCache {
  public:
    ColorCache(const Display &display);
    ~ColorCache(void);

    /*
      Finds a color matching the specified rgb on the given screen.

      The color is allocated if needed; otherwise it is reference
      counted and freed when no more references for the color exist.
    */
    unsigned long find(unsigned int screen, int r, int g, int b);
    /*
      Releases the specified rgb on the given screen.

      If the reference count for a particular color is zero, it will
      be freed by calling clear().
    */
    void release(unsigned int screen, int r, int g, int b);

    /*
      Clears the color cache.  All colors with a zero reference count
      are freed.

      If force is true, then all colors are freed, regardless of the
      reference count.  This is done when destroying the cache.
    */
    void clear(bool force);

  private:
    const Display &_display;

    struct RGB {
      const unsigned int screen;
      const int r, g, b;

      inline RGB(void)
        : screen(~0u), r(-1), g(-1), b(-1)
      { }
      inline RGB(const unsigned int s, const int x, const int y, const int z)
        : screen(s), r(x), g(y), b(z)
      { }
      inline RGB(const RGB &x)
        : screen(x.screen), r(x.r), g(x.g), b(x.b)
      { }

      inline bool operator==(const RGB &x) const
      { return screen == x.screen && r == x.r && g == x.g && b == x.b; }

      inline bool operator<(const RGB &x) const {
        const unsigned long p1 =
          (screen << 24 | r << 16 | g << 8 | b) & 0xffffffff;
        const unsigned long p2 =
          (x.screen << 24 | x.r << 16 | x.g << 8 | x.b) & 0xffffffff;
        return p1 < p2;
      }
    };
    struct PixelRef {
      const unsigned long pixel;
      unsigned int count;
      inline PixelRef(void)
        : pixel(0ul), count(0u)
      { }
      inline PixelRef(const unsigned long x)
        : pixel(x), count(1u)
      { }
    };

    typedef std::map<RGB,PixelRef> Cache;
    typedef Cache::value_type CacheItem;
    Cache cache;
  };

  static ColorCache *colorcache = 0;

  void createColorCache(const Display &display) {
    assert(colorcache == 0);
    colorcache = new ColorCache(display);
  }

  void destroyColorCache(void) {
    delete colorcache;
    colorcache = 0;
  }

} // namespace bt

bt::ColorCache::ColorCache(const Display &display)
  : _display(display)
{ }

bt::ColorCache::~ColorCache(void)
{ clear(true); }

unsigned long bt::ColorCache::find(unsigned int screen, int r, int g, int b) {
  if (r < 0 && r > 255)
    r = 0;
  if (g < 0 && g > 255)
    g = 0;
  if (b < 0 && b > 255)
    b = 0;

  // see if we have allocated this color before
  RGB rgb(screen, r, g, b);
  Cache::iterator it = cache.find(rgb);
  if (it != cache.end()) {
    // found a cached color, use it
    ++it->second.count;

#ifdef COLORCACHE_DEBUG
    fprintf(stderr, "bt::ColorCache: use %02x/%02x/%02x, count %4u\n",
            r, g, b, it->second.count);
#endif // COLORCACHE_DEBUG

    return it->second.pixel;
  }

  XColor xcol;
  xcol.red   = r | r << 8;
  xcol.green = g | g << 8;
  xcol.blue  = b | b << 8;
  xcol.pixel = 0;
  xcol.flags = DoRed | DoGreen | DoBlue;

  Colormap colormap = _display.screenInfo(screen).colormap();
  if (!XAllocColor(_display.XDisplay(), colormap, &xcol)) {
    fprintf(stderr,
            "bt::Color::pixel: cannot allocate color 'rgb:%02x/%02x/%02x'\n",
            r, g, b);
    xcol.pixel = BlackPixel(_display.XDisplay(), screen);
  }

#ifdef COLORCACHE_DEBUG
  fprintf(stderr, "bt::ColorCache: add %02x/%02x/%02x, pixel %08lx\n",
          r, g, b, xcol.pixel);
#endif // COLORCACHE_DEBUG

  cache.insert(CacheItem(rgb, PixelRef(xcol.pixel)));

  return xcol.pixel;
}

void bt::ColorCache::release(unsigned int screen, int r, int g, int b) {
  if (r < 0 && r > 255)
    r = 0;
  if (g < 0 && g > 255)
    g = 0;
  if (b < 0 && b > 255)
    b = 0;

  RGB rgb(screen, r, g, b);
  Cache::iterator it = cache.find(rgb);

  assert(it != cache.end() && it->second.count > 0);
  --it->second.count;

#ifdef COLORCACHE_DEBUG
  fprintf(stderr, "bt::ColorCache: rel %02x/%02x/%02x, count %4u\n",
          r, g, b, it->second.count);
#endif // COLORCACHE_DEBUG
}

void bt::ColorCache::clear(bool force) {
  Cache::iterator it = cache.begin();
  if (it == cache.end())
    return; // nothing to do

#ifdef COLORCACHE_DEBUG
  fprintf(stderr, "bt::ColorCache: clearing cache, %u entries\n",
          cache.size());
#endif // COLORCACHE_DEBUG

  unsigned long *pixels = new unsigned long[ cache.size() ];
  unsigned int screen, count;

  for (screen = 0; screen < _display.screenCount(); ++screen) {
    count = 0;
    it = cache.begin();
    while (it != cache.end()) {
      if (it->second.count != 0 && !force) {
        ++it;
        continue;
      }

#ifdef COLORCACHE_DEBUG
      fprintf(stderr, "bt::ColorCache: fre %02x/%02x/%02x, pixel %08lx\n",
              it->first.r, it->first.g, it->first.b, it->second.pixel);
#endif // COLORCACHE_DEBUG

      pixels[count++] = it->second.pixel;

      Cache::iterator r = it++;
      cache.erase(r);
    }

    if (count > 0u) {
      XFreeColors(_display.XDisplay(),
                  _display.screenInfo(screen).colormap(),
                  pixels, count, 0);
    }
  }

  delete [] pixels;

#ifdef COLORCACHE_DEBUG
  fprintf(stderr, "bt::ColorCache: cleared, %u entries remain\n",
          cache.size());
#endif // COLORCACHE_DEBUG
}

void bt::Color::clearCache(void)
{
  if (colorcache)
    colorcache->clear(false);
}

bt::Color bt::Color::namedColor(const Display &display, unsigned int screen,
                                const std::string &colorname) {
  if (colorname.empty()) {
    fprintf(stderr, "bt::Color::namedColor: empty colorname\n");
    return Color();
  }

  // get rgb values from colorname
  XColor xcol;
  xcol.red   = 0;
  xcol.green = 0;
  xcol.blue  = 0;
  xcol.pixel = 0;

  Colormap colormap = display.screenInfo(screen).colormap();
  if (!XParseColor(display.XDisplay(), colormap, colorname.c_str(), &xcol)) {
    fprintf(stderr, "bt::Color::namedColor: invalid color '%s'\n",
            colorname.c_str());
    return Color();
  }

  return Color(xcol.red >> 8, xcol.green >> 8, xcol.blue >> 8);
}

unsigned long bt::Color::pixel(unsigned int screen) const {
  if (_screen == screen)
    return _pixel; // already allocated on this screen

  assert(colorcache != 0);
  // deallocate() isn't const, so we can't call it from here
  if (_screen != ~0u)
    colorcache->release(_screen, _red, _green, _blue);

  _screen = screen;
  _pixel = colorcache->find(_screen, _red, _green, _blue);
  return _pixel;
}

void bt::Color::deallocate(void) {
  if (_screen == ~0u)
    return; // not allocated

  assert(colorcache != 0);
  colorcache->release(_screen, _red, _green, _blue);

  _screen = ~0u;
  _pixel = 0ul;
}
<commit_msg>Updated Documentation for the Color operations.<commit_after>/*
 * ZebX - Display Management System.
 * Utilizes the tools under the BlackBox system.
 *
 * Color.cc for ZebX - Display Management System
 * Copyright (c) 2018 David Kroell <kroelld.96@gmail.com>
 *
 * Color.cc for Blackbox - an X11 Window manager
 * Copyright (c) 2001 - 2005 Sean 'Shaleh' Perry <shaleh at debian.org>
 * Copyright (c) 1997 - 2000, 2002 - 2005
 *         Bradley T Hughes <bhughes at trolltech.com>
 */

#include "Color.hh"
#include "Display.hh"

#include <map>

#include <X11/Xlib.h>

#include <assert.h>
#include <stdio.h>

//#define COLORCACHE_DEBUG /* Define this to enable debugging for the build. */

namespace bt {

  class ColorCache {
  public:

	  /**
	   * Serialized cache record of the Color object
	   * associated with the application.
	   *
	   * The Display object is used to
	   */
	  ColorCache(const Display &display);
	  ~ColorCache(void);

     /*
      * Finds a color matching the specified rgb on the given screen.
	  *
	  * The color is allocated if needed; otherwise it is reference
	  * counted and freed when no more references for the color exist.
      */
	  unsigned long find(unsigned int screen, int r, int g, int b);

	  /*
       * Releases the specified rgb on the given screen.
	   *
       * If the reference count for a particular color is zero, it will
       * be freed by calling clear().
	   */
	  void release(unsigned int screen, int r, int g, int b);

      /*
       * Clears the color cache.  All colors with a zero reference count
       * are freed.
	   *
       * If force is true, then all colors are freed, regardless of the
       * reference count.  This is done when destroying the cache.
       */
      void clear(bool force);

  private:

      /** Display object to reference the screen display. */
      const Display &_display;

      /**
       * Display object used to handle the color cache
       *
       * Params:
       * 	screen: Screen id to use for the display reference.
       * 	r: Red hex level.
       * 	g: Green hex level.
       * 	b: Blue hex level.
       */
      struct RGB {
    	  const unsigned int screen;
    	  const int r, g, b;

    	  inline RGB(void) : screen(~0u), r(-1), g(-1), b(-1) { }

    	  inline RGB(const unsigned int s, const int x, const int y, const int z) : screen(s), r(x), g(y), b(z) { }

    	  inline RGB(const RGB &x) : screen(x.screen), r(x.r), g(x.g), b(x.b) { }

    	  inline bool operator==(const RGB &x) const { return screen == x.screen && r == x.r && g == x.g && b == x.b; }

    	  inline bool operator<(const RGB &x) const {
    		  const unsigned long p1 = (screen << 24 | r << 16 | g << 8 | b) & 0xffffffff;
    		  const unsigned long p2 = (x.screen << 24 | x.r << 16 | x.g << 8 | x.b) & 0xffffffff; return p1 < p2;
    	  }
      };

      /**
       * Pixel reference to extend the X11 pixel display.
       *
       * Params:
       * 	pixel: pixel id to use as a reference.
       * 	count: Count of the pixel usage to order properly in the Map.
       */
      struct PixelRef {
    	  const unsigned long pixel;
    	  unsigned int count;

    	  inline PixelRef(void) : pixel(0ul), count(0u) { }

    	  inline PixelRef(const unsigned long x) : pixel(x), count(1u) { }
      };

      /** Cache maps Pixel ref to RGB. */
      typedef std::map<RGB,PixelRef> Cache;

      /** Item for the cache map. */
      typedef Cache::value_type CacheItem;

      Cache cache;
  };

  static ColorCache *colorcache = 0;

  /**
   * Method to construct ColorCache object
   *
   * Params:
   * 	display: Object for the ScreenInfo placeholder.
   */
  void createColorCache(const Display &display) {
	  assert(colorcache == 0);
	  colorcache = new ColorCache(display);
  }

  /**
   * Destroy function for the ColorCache object.
   * Mainly used for garbage collection.
   */
  void destroyColorCache(void) {
	  delete colorcache;
	  colorcache = 0;
  }

} // namespace bt

/**
 *  Constructor for the ColorCache object.
 *
 *  Params:
 *  	display: Display placeholder to access ScreenInfo.
 */
bt::ColorCache::ColorCache(const Display &display) : _display(display) { }

/**
 * Destructor for the ColorCache Object.
 */
bt::ColorCache::~ColorCache(void) { clear(true); }

/**
 * Method to find a Screen reference with the given RGB code tagged to it.
 *
 * Params:
 * 		screen: Screen ID to use for the display reference.
 * 		r: Red hex level.
 * 		g: Green hex level.
 * 		b: Blue hex level.
 */
unsigned long bt::ColorCache::find(unsigned int screen, int r, int g, int b) {
	if (r < 0 && r > 255)
		r = 0;

	if (g < 0 && g > 255)
		g = 0;

	if (b < 0 && b > 255)
		b = 0;

	// see if we have allocated this color before
	RGB rgb(screen, r, g, b);

	// iterator to loop through the entire Map.
	Cache::iterator it = cache.find(rgb);

	// loop and basecase.
	if (it != cache.end()) {

		// found a cached color, use it
		++it->second.count;

		// Debugging statement.
		#ifdef COLORCACHE_DEBUG
			fprintf(stderr, "bt::ColorCache: use %02x/%02x/%02x, count %4u\n",
					r, g, b, it->second.count);
		#endif // COLORCACHE_DEBUG

		return it->second.pixel;
	}

	// We haven't found the Color in the Map.
	// We need to

	XColor xcol;
	xcol.red   = r | r << 8;
	xcol.green = g | g << 8;
	xcol.blue  = b | b << 8;
	xcol.pixel = 0;
	xcol.flags = DoRed | DoGreen | DoBlue;

	// Get the color map.
	Colormap colormap = _display.screenInfo(screen).colormap();

	// If we can't allocate the color with the display, then display a black pixel.
	if (!XAllocColor(_display.XDisplay(), colormap, &xcol)) {
		fprintf(stderr,
				"bt::Color::pixel: cannot allocate color 'rgb:%02x/%02x/%02x'\n",
				r, g, b);

		xcol.pixel = BlackPixel(_display.XDisplay(), screen);
	}

#ifdef COLORCACHE_DEBUG
  fprintf(stderr, "bt::ColorCache: add %02x/%02x/%02x, pixel %08lx\n",
          r, g, b, xcol.pixel);
#endif // COLORCACHE_DEBUG

  	// Insert the Pixel Reference to the cache.
    cache.insert(CacheItem(rgb, PixelRef(xcol.pixel)));

    // Return the pixel.
    return xcol.pixel;
}

void bt::ColorCache::release(unsigned int screen, int r, int g, int b) {
	if (r < 0 && r > 255)
		r = 0;

	if (g < 0 && g > 255)
		g = 0;

	if (b < 0 && b > 255)
		b = 0;

	RGB rgb(screen, r, g, b);

	// Iterator to look through and release the Color object.
	Cache::iterator it = cache.find(rgb);

	assert(it != cache.end() && it->second.count > 0);

	// Decrement the count of the pixel usage.
	--it->second.count;

#ifdef COLORCACHE_DEBUG
  fprintf(stderr, "bt::ColorCache: rel %02x/%02x/%02x, count %4u\n",
          r, g, b, it->second.count);
#endif // COLORCACHE_DEBUG

}

/**
 * Clear the color cache for garbage collection.
 *
 * Params:
 * 		force: Force the object to destruct?
 */
void bt::ColorCache::clear(bool force) {

	// Iterator to loop through cache.
	Cache::iterator it = cache.begin();

	// End loop.
	if (it == cache.end())
		return; // nothing to do

#ifdef COLORCACHE_DEBUG
  fprintf(stderr, "bt::ColorCache: clearing cache, %u entries\n",
          cache.size());
#endif // COLORCACHE_DEBUG

    // Array of pixels to hold.
  	unsigned long *pixels = new unsigned long[ cache.size() ];

  	unsigned int screen, count;

  	// loop through the screens.
  	for (screen = 0; screen < _display.screenCount(); ++screen) {

  		// Begin iterator for the cache.
  		count = 0;
  		it = cache.begin();

  		// Loop through and increment the count.
  		while (it != cache.end()) {
  			if (it->second.count != 0 && !force) {
  				++it;
  				continue;
  			}

#ifdef COLORCACHE_DEBUG
      fprintf(stderr, "bt::ColorCache: fre %02x/%02x/%02x, pixel %08lx\n",
              it->first.r, it->first.g, it->first.b, it->second.pixel);
#endif // COLORCACHE_DEBUG

      	    // Populate pixel index.
      	    pixels[count++] = it->second.pixel;

      	    // erase the ColorCache object and increment the iterator.
      	    Cache::iterator r = it++;
      	    cache.erase(r);
  		}

  		// If the count is greater than the referenced pixel count.
  		// Free the cells represented by the pixels
  		if (count > 0u) {

  			XFreeColors(
  					_display.XDisplay(),
  					_display.screenInfo(screen).colormap(),
					pixels, count, 0
				);
  		}
  	}

  	// Get rid of the pixels array.
  	delete [] pixels;

#ifdef COLORCACHE_DEBUG
  fprintf(stderr, "bt::ColorCache: cleared, %u entries remain\n",
          cache.size());
#endif // COLORCACHE_DEBUG
}

// Clear the ColorCache
void bt::Color::clearCache(void) {
	if (colorcache)
		colorcache->clear(false);
}

/**
 * Get a Color object from the named Object.
 *
 * Params:
 * 		display: Display object to reference.
 * 		screen: Screen to reference.
 * 		colorname: name of color to convert from.
 *
 * See:
 * 		XParseColor(...)
 */
bt::Color bt::Color::namedColor(const Display &display, unsigned int screen,
                                const std::string &colorname) {

	// Make sure there's no empty Color.
	if (colorname.empty()) {
		fprintf(stderr, "bt::Color::namedColor: empty colorname\n");
		return Color();
	}

	// get rgb values from colorname
	XColor xcol;
	xcol.red   = 0;
	xcol.green = 0;
	xcol.blue  = 0;
	xcol.pixel = 0;

	// Color map to parse from.
	Colormap colormap = display.screenInfo(screen).colormap();

	// If we can't parse the color name then don't return a specific color.
	if (!XParseColor(display.XDisplay(), colormap, colorname.c_str(), &xcol)) {
		fprintf(stderr, "bt::Color::namedColor: invalid color '%s'\n",
				colorname.c_str());

		return Color();
	}

	// Return a color from the referenced map.
	return Color(xcol.red >> 8, xcol.green >> 8, xcol.blue >> 8);
}

/**
 * Get the Pixel associated with the preset RGB values.
 *
 * params:
 * 		screen: Which screen ID to look at.
 *
 */
unsigned long bt::Color::pixel(unsigned int screen) const {

	if (_screen == screen)
		return _pixel; // already allocated on this screen

	assert(colorcache != 0);

	// deallocate() isn't const, so we can't call it from here
	if (_screen != ~0u)
		colorcache->release(_screen, _red, _green, _blue); // But... Deallocate...

	//Assign the screen value to the preset.
	_screen = screen;

	// Find the correct pixel and return it.
	_pixel = colorcache->find(_screen, _red, _green, _blue);
	return _pixel;
}

/**
 * deallocate the screen and pixel values for the object.
 * Bring back to normal use.
 *
 */
void bt::Color::deallocate(void) {
	if (_screen == ~0u)
		return; // not allocated

	assert(colorcache != 0);

	// Release a pixel of the screen associated with the RGB
	colorcache->release(_screen, _red, _green, _blue);

	// Reset the screen and pixel values.
	_screen = ~0u;
	_pixel = 0ul;
}
<|endoftext|>


<commit_before>#include "clustering/administration/main/directory_lock.hpp"

#ifndef _MSC_VER
#include <dirent.h>
#include <sys/file.h>
#else
#include <filesystem>
#include <direct.h>
#endif

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

#include <stdexcept>

#include "arch/io/disk.hpp"

bool check_existence(const base_path_t& base_path) {
    return 0 == access(base_path.path().c_str(), F_OK);
}

bool check_dir_emptiness(const base_path_t& base_path) {
#ifdef _MSC_VER
    for (auto it : std::tr2::sys::directory_iterator(base_path.path())) {
        return false;
    }
    return true;
#else
    DIR *dp;
    struct dirent *ep;

    dp = opendir(base_path.path().c_str());
    if (dp == NULL) {
        throw directory_open_failed_exc_t(get_errno(), base_path);
    }

    set_errno(0);

    // cpplint is wrong about readdir here, because POSIX guarantees we're not
    // sharing a static buffer with other threads on the system.  Even better, OS X
    // and Linux glibc both allocate per-directory buffers.  readdir_r is unsafe
    // because you can't specify the length of the struct dirent buffer you pass in
    // to it.  See http://elliotth.blogspot.com/2012/10/how-not-to-use-readdirr3.html
    while ((ep = readdir(dp)) != NULL) {  // NOLINT(runtime/threadsafe_fn)
        if (strcmp(ep->d_name, ".") != 0 && strcmp(ep->d_name, "..") != 0) {
            closedir(dp);
            return false;
        }
    }
    guarantee_err(get_errno() == 0, "Error while reading directory");

    closedir(dp);
    return true;
#endif
}

directory_lock_t::directory_lock_t(const base_path_t &path, bool create, bool *created_out) :
    directory_path(path),
    created(false),
    initialize_done(false) {

    *created_out = false;
    bool dir_exists = check_existence(directory_path);

    if (!dir_exists) {
        if (!create) {
            throw directory_missing_exc_t(directory_path);
        }
        int mkdir_res;
        do {
#if defined(__MINGW32__)
            mkdir_res = mkdir(directory_path.path().c_str());
#elif defined(_WIN32)
            mkdir_res = _mkdir(directory_path.path().c_str());
#else
            mkdir_res = mkdir(directory_path.path().c_str(), 0755);
#endif
        } while (mkdir_res == -1 && get_errno() == EINTR);
        if (mkdir_res != 0) {
            throw directory_create_failed_exc_t(get_errno(), directory_path);
        }
        created = true;
        *created_out = true;

        // Call fsync() on the parent directory to guarantee that the newly
        // created directory's directory entry is persisted to disk.
        warn_fsync_parent_directory(directory_path.path().c_str());
    } else if (create && check_dir_emptiness(directory_path)) {
        created = true;
        *created_out = true;
    }

#ifdef _WIN32
    // TODO WINDOWS: issue #5165
    directory_fd.reset(CreateFile(directory_path.path().c_str(), GENERIC_READ, 0, NULL,
                                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL));
    if (directory_fd.get() == INVALID_FD) {
        logERR("CreateFile failed: %s", winerr_string(GetLastError()).c_str());
        throw directory_open_failed_exc_t(EIO, directory_path);
    }
#else
    directory_fd.reset(::open(directory_path.path().c_str(), O_RDONLY));
    if (directory_fd.get() == INVALID_FD) {
        throw directory_open_failed_exc_t(get_errno(), directory_path);
    }
    if (flock(directory_fd.get(), LOCK_EX | LOCK_NB) != 0) {
        throw directory_locked_exc_t(directory_path);
    }
#endif
}

directory_lock_t::~directory_lock_t() {
    // Only delete the directory if we created it and haven't finished initialization
    if (created && !initialize_done) {
        remove_directory_recursive(directory_path.path().c_str());
    }
}

void directory_lock_t::directory_initialized() {
    guarantee(directory_fd.get() != INVALID_FD);
    initialize_done = true;
}

#ifndef _WIN32
void directory_lock_t::change_ownership(gid_t group_id, const std::string &group_name,
                                        uid_t user_id, const std::string &user_name) {
    if (group_id != INVALID_GID || user_id != INVALID_UID) {
        if (fchown(directory_fd.get(), user_id, group_id) != 0) {
            throw std::runtime_error(strprintf("Failed to change ownership of data "
                                               "directory '%s' to '%s:%s': %s",
                                               directory_path.path().c_str(),
                                               user_name.c_str(),
                                               group_name.c_str(),
                                               errno_string(get_errno()).c_str()));
        }
    }
}
#endif
<commit_msg>improve directory locking<commit_after>#include "clustering/administration/main/directory_lock.hpp"

#ifndef _MSC_VER
#include <dirent.h>
#include <sys/file.h>
#else
#include <filesystem>
#include <direct.h>
#endif

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

#include <stdexcept>

#include "arch/io/disk.hpp"

#ifdef _WIN32
#define LOCK_FILE_NAME "dirlock"
#endif

bool check_existence(const base_path_t& base_path) {
    return 0 == access(base_path.path().c_str(), F_OK);
}

bool check_dir_emptiness(const base_path_t& base_path) {
#ifdef _MSC_VER
    for (auto it : std::tr2::sys::directory_iterator(base_path.path())) {
        return false;
    }
    return true;
#else
    DIR *dp;
    struct dirent *ep;

    dp = opendir(base_path.path().c_str());
    if (dp == NULL) {
        throw directory_open_failed_exc_t(get_errno(), base_path);
    }

    set_errno(0);

    // cpplint is wrong about readdir here, because POSIX guarantees we're not
    // sharing a static buffer with other threads on the system.  Even better, OS X
    // and Linux glibc both allocate per-directory buffers.  readdir_r is unsafe
    // because you can't specify the length of the struct dirent buffer you pass in
    // to it.  See http://elliotth.blogspot.com/2012/10/how-not-to-use-readdirr3.html
    while ((ep = readdir(dp)) != NULL) {  // NOLINT(runtime/threadsafe_fn)
        if (strcmp(ep->d_name, ".") != 0 && strcmp(ep->d_name, "..") != 0) {
            closedir(dp);
            return false;
        }
    }
    guarantee_err(get_errno() == 0, "Error while reading directory");

    closedir(dp);
    return true;
#endif
}

directory_lock_t::directory_lock_t(const base_path_t &path, bool create, bool *created_out) :
    directory_path(path),
    created(false),
    initialize_done(false) {

    *created_out = false;
    bool dir_exists = check_existence(directory_path);

    if (!dir_exists) {
        if (!create) {
            throw directory_missing_exc_t(directory_path);
        }
        int mkdir_res;
        do {
#if defined(__MINGW32__)
            mkdir_res = mkdir(directory_path.path().c_str());
#elif defined(_WIN32)
            mkdir_res = _mkdir(directory_path.path().c_str());
#else
            mkdir_res = mkdir(directory_path.path().c_str(), 0755);
#endif
        } while (mkdir_res == -1 && get_errno() == EINTR);
        if (mkdir_res != 0) {
            throw directory_create_failed_exc_t(get_errno(), directory_path);
        }
        created = true;
        *created_out = true;

        // Call fsync() on the parent directory to guarantee that the newly
        // created directory's directory entry is persisted to disk.
        warn_fsync_parent_directory(directory_path.path().c_str());
    } else if (create && check_dir_emptiness(directory_path)) {
        created = true;
        *created_out = true;
    }

#ifdef _WIN32
    directory_fd.reset(CreateFile((directory_path.path() + "\\" LOCK_FILE_NAME).c_str(),
                                  GENERIC_READ | GENERIC_WRITE, 0, NULL,
                                  CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN | FILE_FLAG_DELETE_ON_CLOSE, NULL));
    if (directory_fd.get() == INVALID_FD) {
        logERR("CreateFile failed: %s", winerr_string(GetLastError()).c_str());
        throw directory_open_failed_exc_t(EIO, directory_path);
    }
#else
    directory_fd.reset(::open(directory_path.path().c_str(), O_RDONLY));
    if (directory_fd.get() == INVALID_FD) {
        throw directory_open_failed_exc_t(get_errno(), directory_path);
    }
    if (flock(directory_fd.get(), LOCK_EX | LOCK_NB) != 0) {
        throw directory_locked_exc_t(directory_path);
    }
#endif
}

directory_lock_t::~directory_lock_t() {
    // Only delete the directory if we created it and haven't finished initialization
    if (created && !initialize_done) {
#ifdef _WIN32
        // On windows, the directory lock is a file inside the directory
        // TODO ATN: but this unlocks the directory!
        directory_fd.reset();
#endif
        remove_directory_recursive(directory_path.path().c_str());
    }
}

void directory_lock_t::directory_initialized() {
    guarantee(directory_fd.get() != INVALID_FD);
    initialize_done = true;
}

#ifndef _WIN32
void directory_lock_t::change_ownership(gid_t group_id, const std::string &group_name,
                                        uid_t user_id, const std::string &user_name) {
    if (group_id != INVALID_GID || user_id != INVALID_UID) {
        if (fchown(directory_fd.get(), user_id, group_id) != 0) {
            throw std::runtime_error(strprintf("Failed to change ownership of data "
                                               "directory '%s' to '%s:%s': %s",
                                               directory_path.path().c_str(),
                                               user_name.c_str(),
                                               group_name.c_str(),
                                               errno_string(get_errno()).c_str()));
        }
    }
}
#endif
<|endoftext|>


<commit_before>
#include <EagleLib/rcc/shared_ptr.hpp>
#include <EagleLib/nodes/NodeManager.h>
#include "EagleLib/nodes/Node.h"
#include "EagleLib/Plugins.h"
#include <EagleLib/DataStreamManager.h>
#include <EagleLib/Logging.h>
#include <signal.h>
#include <signals/logging.hpp>

#include <boost/program_options.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/common.hpp>
#include <boost/log/exceptions.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/filesystem.hpp>
#include <boost/version.hpp>
#include <boost/tokenizer.hpp>

#include <parameters/Persistence/TextSerializer.hpp>

void PrintNodeTree(EagleLib::Nodes::Node* node, int depth)
{
    for(int i = 0; i < depth; ++i)
    {
        std::cout << "=";
    }
    std::cout << node->getFullTreeName() << std::endl;
    for(int i = 0; i < node->children.size(); ++i)
    {
        PrintNodeTree(node->children[i].get(), depth + 1);
    }
}
static volatile bool quit;
void sig_handler(int s)
{
    //std::cout << "Caught signal " << s << std::endl;
	BOOST_LOG_TRIVIAL(error) << "Caught signal " << s;
    quit = true;
}

int main(int argc, char* argv[])
{
	signal(SIGINT, sig_handler);
	signal(SIGILL, sig_handler);
	signal(SIGTERM, sig_handler);

    boost::program_options::options_description desc("Allowed options");

    //boost::log::add_file_log(boost::log::keywords::file_name = "SimpleConsole%N.log", boost::log::keywords::rotation_size = 10 * 1024 * 1024);
    EagleLib::SetupLogging();

    desc.add_options()
        ("file", boost::program_options::value<std::string>(), "Required - File to load for processing")
        ("config", boost::program_options::value<std::string>(), "Required - File containing node structure")
        ("plugins", boost::program_options::value<boost::filesystem::path>(), "Path to additional plugins to load")
		("log", boost::program_options::value<std::string>()->default_value("info"), "Logging verbosity. trace, debug, info, warning, error, fatal")
        ("mode", boost::program_options::value<std::string>()->default_value("batch"), "Processing mode, options are interactive or batch")
        ;

    boost::program_options::variables_map vm;
    boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);

    if((!vm.count("config") || !vm.count("file")) && vm["mode"].as<std::string>() == "batch")
    {
        LOG(info) << "Batch mode selected but \"file\" and \"config\" options not set";
        std::cout << desc;
        return 1;
    }
	if (vm.count("log"))
	{
		std::string verbosity = vm["log"].as<std::string>();
		if (verbosity == "trace")
			boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::trace);
		if (verbosity == "debug")
			boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::debug);
		if (verbosity == "info")
			boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::info);
		if (verbosity == "warning")
			boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::warning);
		if (verbosity == "error")
			boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::error);
		if (verbosity == "fatal")
			boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::fatal);
	}else
    {
    	boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::info);
    }
	boost::filesystem::path currentDir = boost::filesystem::current_path();
#ifdef _DEBUG
    currentDir.append("../Debug");
#else
    currentDir.append("../RelWithDebInfo");
#endif
    boost::filesystem::directory_iterator end_itr;

    for(boost::filesystem::directory_iterator itr(currentDir); itr != end_itr; ++itr)
    {
        if(boost::filesystem::is_regular_file(itr->path()))
        {
#ifdef _MSC_VER
            if(itr->path().extension() == ".dll")
#else
            if(itr->path().extension() == ".so")
#endif
            {
                std::string file = itr->path().string();
                EagleLib::loadPlugin(file);
            }else
            {
                std::cout << itr->path().extension() << std::endl;
            }
        }
    }

    if(vm.count("plugins"))
    {
        currentDir = boost::filesystem::path(vm["plugins"].as<boost::filesystem::path>());
        for (boost::filesystem::directory_iterator itr(currentDir); itr != end_itr; ++itr)
        {
            if (boost::filesystem::is_regular_file(itr->path()))
            {
#ifdef _MSC_VER
                if (itr->path().extension() == ".dll")
#else
                if (itr->path().extension() == ".so")
#endif
                {
                    std::string file = itr->path().string();
                    EagleLib::loadPlugin(file);
                }
                else
                {
                    std::cout << itr->path().extension() << std::endl;
                }
            }
        }
    }

    if(vm["mode"].as<std::string>() == "batch")
    {
        quit = false;
        std::string document = vm["file"].as<std::string>();
        LOG(info) << "Loading file: " << document;
        std::string configFile = vm["config"].as<std::string>();
        LOG(info) << "Loading config file " << configFile;

        auto stream = EagleLib::DataStreamManager::instance()->create_stream();
        stream->LoadDocument(document);

        auto nodes = EagleLib::NodeManager::getInstance().loadNodes(configFile);
        stream->AddNode(nodes);

        LOG(info) << "Loaded " << nodes.size() << " top level nodes";
        for(int i = 0; i < nodes.size(); ++i)
        {
            PrintNodeTree(nodes[i].get(), 1);
        }
        stream->process();
    }else
    {
        std::vector<std::shared_ptr<EagleLib::DataStream>> _dataStreams;
        EagleLib::DataStream* current_stream = nullptr;
        EagleLib::Nodes::Node* current_node = nullptr;

        auto print_options = []()->void
        {
            std::cout <<
                "- Options: \n "
                " - LoadFile {document}                       -- Create a frame grabber for a document \n"
                " - Add {node}                                -- Add a node to the current selected object\n"
                " - List {nodes}                              -- List all possible nodes that can be constructed\n"
                " - Print {streams,nodes,parameters, current} -- Prints the current streams, nodes in current stream, \n"
                "                                                or parameters of current node\n"
                " - Select {node,stream}                      -- Select a node by name (relative to current selection\n"
                "                                                or absolute, or a stream by index)\n"
                " - Save                                      -- Save node configuration\n"
                " - Load                                      -- Load node configuration\n"
                " - Help                                      -- Print this help\n"
                " - Quit                                      -- Close program and cleanup\n";
        };

        std::map<std::string, std::function<void(std::string)>> function_map;
        function_map["LoadFile"] = [&_dataStreams](std::string doc)->void
        {
            if(EagleLib::DataStream::CanLoadDocument(doc))
            {
                LOG(debug) << "Found a frame grabber which can load " << doc;
                auto stream = EagleLib::DataStreamManager::instance()->create_stream();
                if(stream->LoadDocument(doc))
                {
                    _dataStreams.push_back(stream);
                }else
                {
                    LOG(warning) << "Unable to load document";
                }
            }else
            {
                LOG(warning) << "Unable to find a frame grabber which can load " << doc;
            }
        };
        function_map["Quit"] = [](std::string)->void
        {
            quit = true;
        };
        function_map["Print"] = [&_dataStreams, &current_stream, &current_node](std::string what)->void
        {
            if(what == "streams")
            {
                for(auto& itr : _dataStreams)
                {
                    std::cout << " - " << itr->get_stream_id() << " - " << itr->GetFrameGrabber()->GetSourceFilename() << "\n";
                }
            }
            if(what == "nodes")
            {
                if(current_stream)
                {
                    auto nodes = current_stream->GetNodes();
                    for(auto& node : nodes)
                    {
                        PrintNodeTree(node.get(), 0);
                    }
                }
                else if(current_node)
                {
                    PrintNodeTree(current_node, 0);
                }
            }
            if(what == "parameters")
            {
                std::vector<std::shared_ptr<Parameters::Parameter>> parameters;
                if(current_node)
                {
                    parameters = current_node->getParameters();
                }
                if(current_stream)
                {
                    parameters = current_stream->GetFrameGrabber()->getParameters();
                }
                for(auto& itr : parameters)
                {
                    std::stringstream ss;
                    try
                    {
                        Parameters::Persistence::Text::Serialize(&ss, itr.get());
                        std::cout << " - " << itr->GetTreeName() << ": " << ss.str() << "\n";
                    }catch(...)
                    {
                        std::cout << " - " << itr->GetTreeName() << "\n";
                    }
                }
            }
            if(what == "current")
            {
                if(current_stream)
                {
                    std::cout << " - Current stream: " << current_stream->GetFrameGrabber()->GetSourceFilename() << "\n";
                    return;
                }
                if(current_node)
                {
                    std::cout << " - Current node: " << current_node->getFullTreeName() << "\n";
                    return;
                }
                std::cout << "Nothing currently selected\n";
            }
        };
        function_map["Select"] = [&_dataStreams,&current_stream, &current_node](std::string what)
        {
            int idx = -1;
            std::string name;

            try
            {
                idx =  boost::lexical_cast<int>(what);
            }catch(...)
            {
                idx = -1;
            }
            if(idx == -1)
            {
                name = what;
            }
            if(idx != -1)
            {
                LOG(info) << "Selecting stream " << idx;
                for(auto& itr : _dataStreams)
                {
                    if(itr->get_stream_id() == idx)
                    {
                        current_stream = itr.get();
                        current_node = nullptr;
                        return;
                    }
                }
            }
            if(current_stream)
            {
                // look for a node with this name, relative then look absolute
                auto nodes = current_stream->GetNodes();
                for(auto& node : nodes)
                {
                    if(node->getTreeName() == what)
                    {
                        current_stream = nullptr;
                        current_node = node.get();
                        return;
                    }
                }
                // parse name and try to find absolute path to node

            }

        };
        function_map["Help"] = [&print_options](std::string)->void{print_options();};
        function_map["List"] = [](std::string)->void
        {
            auto nodes = EagleLib::NodeManager::getInstance().getConstructableNodes();
            for(auto& node : nodes)
            {
                std::cout << " - " << node << "\n";
            }
        };
        function_map["Add"] = [&current_node, &current_stream](std::string name)->void
        {
            auto node = EagleLib::NodeManager::getInstance().addNode(name);
            if(!node)
            {
                return;
            }
            if(current_node)
            {
                current_node->addChild(node);
                return;
            }
            if(current_stream)
            {
                current_stream->AddNode(node);
                return;
            }
        };

        print_options();

        while(!quit)
        {
            std::string command_line;
            std::getline(std::cin, command_line);
            int count = 0;
	        std::stringstream ss;
            ss << command_line;
            std::string command;
            std::getline(ss, command, ' ');
            if(function_map.count(command))
            {
                std::string rest;
                ss >> rest;
                LOG(debug) << "Executing command (" << command << ") with arguments: " << rest;
                function_map[command](rest);
            }else
            {
                LOG(warning) << "Invalid command: " << command_line;
                print_options();
            }
        }
        LOG(info) << "Shutting down";
    }

    return 0;
}
<commit_msg>Linux fixes.<commit_after>
#include <EagleLib/rcc/shared_ptr.hpp>
#include <EagleLib/nodes/NodeManager.h>
#include "EagleLib/nodes/Node.h"
#include "EagleLib/Plugins.h"
#include <EagleLib/DataStreamManager.h>
#include <EagleLib/Logging.h>
#include <signal.h>
#include <signals/logging.hpp>

#include <boost/program_options.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/common.hpp>
#include <boost/log/exceptions.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/filesystem.hpp>
#include <boost/version.hpp>
#include <boost/tokenizer.hpp>

#include <parameters/Persistence/TextSerializer.hpp>

void PrintNodeTree(EagleLib::Nodes::Node* node, int depth)
{
    for(int i = 0; i < depth; ++i)
    {
        std::cout << "=";
    }
    std::cout << node->getFullTreeName() << std::endl;
    for(int i = 0; i < node->children.size(); ++i)
    {
        PrintNodeTree(node->children[i].get(), depth + 1);
    }
}
static volatile bool quit;
void sig_handler(int s)
{
    //std::cout << "Caught signal " << s << std::endl;
	BOOST_LOG_TRIVIAL(error) << "Caught signal " << s;
    quit = true;
}

int main(int argc, char* argv[])
{
	signal(SIGINT, sig_handler);
	signal(SIGILL, sig_handler);
	signal(SIGTERM, sig_handler);

    boost::program_options::options_description desc("Allowed options");

    //boost::log::add_file_log(boost::log::keywords::file_name = "SimpleConsole%N.log", boost::log::keywords::rotation_size = 10 * 1024 * 1024);
    EagleLib::SetupLogging();

    desc.add_options()
        ("file", boost::program_options::value<std::string>(), "Required - File to load for processing")
        ("config", boost::program_options::value<std::string>(), "Required - File containing node structure")
        ("plugins", boost::program_options::value<boost::filesystem::path>(), "Path to additional plugins to load")
		("log", boost::program_options::value<std::string>()->default_value("info"), "Logging verbosity. trace, debug, info, warning, error, fatal")
        ("mode", boost::program_options::value<std::string>()->default_value("batch"), "Processing mode, options are interactive or batch")
        ;

    boost::program_options::variables_map vm;
    boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);

    if((!vm.count("config") || !vm.count("file")) && vm["mode"].as<std::string>() == "batch")
    {
        LOG(info) << "Batch mode selected but \"file\" and \"config\" options not set";
        std::cout << desc;
        return 1;
    }
	if (vm.count("log"))
	{
		std::string verbosity = vm["log"].as<std::string>();
		if (verbosity == "trace")
			boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::trace);
		if (verbosity == "debug")
			boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::debug);
		if (verbosity == "info")
			boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::info);
		if (verbosity == "warning")
			boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::warning);
		if (verbosity == "error")
			boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::error);
		if (verbosity == "fatal")
			boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::fatal);
	}else
    {
    	boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::info);
    }
	boost::filesystem::path currentDir = boost::filesystem::current_path();
#ifdef _MSC_VER
#ifdef _DEBUG
    currentDir = boost::filesystem::path(currentDir.string() + "../Debug");
#else
    currentDir = boost::filesystem::path(currentDir.string() + "../RelWithDebInfo");
#endif
#else
    currentDir = boost::filesystem::path(currentDir.string() + "/Plugins");
#endif
    boost::filesystem::directory_iterator end_itr;

    for(boost::filesystem::directory_iterator itr(currentDir); itr != end_itr; ++itr)
    {
        if(boost::filesystem::is_regular_file(itr->path()))
        {
#ifdef _MSC_VER
            if(itr->path().extension() == ".dll")
#else
            if(itr->path().extension() == ".so")
#endif
            {
                std::string file = itr->path().string();
                EagleLib::loadPlugin(file);
            }else
            {
                std::cout << itr->path().extension() << std::endl;
            }
        }
    }

    if(vm.count("plugins"))
    {
        currentDir = boost::filesystem::path(vm["plugins"].as<boost::filesystem::path>());
        for (boost::filesystem::directory_iterator itr(currentDir); itr != end_itr; ++itr)
        {
            if (boost::filesystem::is_regular_file(itr->path()))
            {
#ifdef _MSC_VER
                if (itr->path().extension() == ".dll")
#else
                if (itr->path().extension() == ".so")
#endif
                {
                    std::string file = itr->path().string();
                    EagleLib::loadPlugin(file);
                }
                else
                {
                    std::cout << itr->path().extension() << std::endl;
                }
            }
        }
    }

    if(vm["mode"].as<std::string>() == "batch")
    {
        quit = false;
        std::string document = vm["file"].as<std::string>();
        LOG(info) << "Loading file: " << document;
        std::string configFile = vm["config"].as<std::string>();
        LOG(info) << "Loading config file " << configFile;

        auto stream = EagleLib::DataStreamManager::instance()->create_stream();
        stream->LoadDocument(document);

        auto nodes = EagleLib::NodeManager::getInstance().loadNodes(configFile);
        stream->AddNode(nodes);

        LOG(info) << "Loaded " << nodes.size() << " top level nodes";
        for(int i = 0; i < nodes.size(); ++i)
        {
            PrintNodeTree(nodes[i].get(), 1);
        }
        stream->process();
    }else
    {
        std::vector<std::shared_ptr<EagleLib::DataStream>> _dataStreams;
        EagleLib::DataStream* current_stream = nullptr;
        EagleLib::Nodes::Node* current_node = nullptr;

        auto print_options = []()->void
        {
            std::cout <<
                "- Options: \n "
                " - LoadFile {document}                       -- Create a frame grabber for a document \n"
                " - Add {node}                                -- Add a node to the current selected object\n"
                " - List {nodes}                              -- List all possible nodes that can be constructed\n"
                " - Print {streams,nodes,parameters, current} -- Prints the current streams, nodes in current stream, \n"
                "                                                or parameters of current node\n"
                " - Select {node,stream}                      -- Select a node by name (relative to current selection\n"
                "                                                or absolute, or a stream by index)\n"
                " - Save                                      -- Save node configuration\n"
                " - Load                                      -- Load node configuration\n"
                " - Help                                      -- Print this help\n"
                " - Quit                                      -- Close program and cleanup\n";
        };

        std::map<std::string, std::function<void(std::string)>> function_map;
        function_map["LoadFile"] = [&_dataStreams](std::string doc)->void
        {
            if(EagleLib::DataStream::CanLoadDocument(doc))
            {
                LOG(debug) << "Found a frame grabber which can load " << doc;
                auto stream = EagleLib::DataStreamManager::instance()->create_stream();
                if(stream->LoadDocument(doc))
                {
                    _dataStreams.push_back(stream);
                }else
                {
                    LOG(warning) << "Unable to load document";
                }
            }else
            {
                LOG(warning) << "Unable to find a frame grabber which can load " << doc;
            }
        };
        function_map["Quit"] = [](std::string)->void
        {
            quit = true;
        };
        function_map["Print"] = [&_dataStreams, &current_stream, &current_node](std::string what)->void
        {
            if(what == "streams")
            {
                for(auto& itr : _dataStreams)
                {
                    std::cout << " - " << itr->get_stream_id() << " - " << itr->GetFrameGrabber()->GetSourceFilename() << "\n";
                }
            }
            if(what == "nodes")
            {
                if(current_stream)
                {
                    auto nodes = current_stream->GetNodes();
                    for(auto& node : nodes)
                    {
                        PrintNodeTree(node.get(), 0);
                    }
                }
                else if(current_node)
                {
                    PrintNodeTree(current_node, 0);
                }
            }
            if(what == "parameters")
            {
                std::vector<std::shared_ptr<Parameters::Parameter>> parameters;
                if(current_node)
                {
                    parameters = current_node->getParameters();
                }
                if(current_stream)
                {
                    parameters = current_stream->GetFrameGrabber()->getParameters();
                }
                for(auto& itr : parameters)
                {
                    std::stringstream ss;
                    try
                    {
                        Parameters::Persistence::Text::Serialize(&ss, itr.get());
                        std::cout << " - " << itr->GetTreeName() << ": " << ss.str() << "\n";
                    }catch(...)
                    {
                        std::cout << " - " << itr->GetTreeName() << "\n";
                    }
                }
            }
            if(what == "current")
            {
                if(current_stream)
                {
                    std::cout << " - Current stream: " << current_stream->GetFrameGrabber()->GetSourceFilename() << "\n";
                    return;
                }
                if(current_node)
                {
                    std::cout << " - Current node: " << current_node->getFullTreeName() << "\n";
                    return;
                }
                std::cout << "Nothing currently selected\n";
            }
        };
        function_map["Select"] = [&_dataStreams,&current_stream, &current_node](std::string what)
        {
            int idx = -1;
            std::string name;

            try
            {
                idx =  boost::lexical_cast<int>(what);
            }catch(...)
            {
                idx = -1;
            }
            if(idx == -1)
            {
                name = what;
            }
            if(idx != -1)
            {
                LOG(info) << "Selecting stream " << idx;
                for(auto& itr : _dataStreams)
                {
                    if(itr->get_stream_id() == idx)
                    {
                        current_stream = itr.get();
                        current_node = nullptr;
                        return;
                    }
                }
            }
            if(current_stream)
            {
                // look for a node with this name, relative then look absolute
                auto nodes = current_stream->GetNodes();
                for(auto& node : nodes)
                {
                    if(node->getTreeName() == what)
                    {
                        current_stream = nullptr;
                        current_node = node.get();
                        return;
                    }
                }
                // parse name and try to find absolute path to node

            }

        };
        function_map["Help"] = [&print_options](std::string)->void{print_options();};
        function_map["List"] = [](std::string)->void
        {
            auto nodes = EagleLib::NodeManager::getInstance().getConstructableNodes();
            for(auto& node : nodes)
            {
                std::cout << " - " << node << "\n";
            }
        };
        function_map["Add"] = [&current_node, &current_stream](std::string name)->void
        {
            auto node = EagleLib::NodeManager::getInstance().addNode(name);
            if(!node)
            {
                return;
            }
            if(current_node)
            {
                current_node->addChild(node);
                return;
            }
            if(current_stream)
            {
                current_stream->AddNode(node);
                return;
            }
        };

        print_options();

        while(!quit)
        {
            std::string command_line;
            std::getline(std::cin, command_line);
            int count = 0;
	        std::stringstream ss;
            ss << command_line;
            std::string command;
            std::getline(ss, command, ' ');
            if(function_map.count(command))
            {
                std::string rest;
                ss >> rest;
                LOG(debug) << "Executing command (" << command << ") with arguments: " << rest;
                function_map[command](rest);
            }else
            {
                LOG(warning) << "Invalid command: " << command_line;
                print_options();
            }
        }
        LOG(info) << "Shutting down";
    }

    return 0;
}
<|endoftext|>