<commit_before>#include <sal/program_options/config_reader.hpp>
#include <sal/program_options/error.hpp>
#include <sal/assert.hpp>
#include <cctype>
#include <deque>
#include <istream>

namespace sal { namespace program_options {
__sal_begin

namespace {

constexpr bool is_json_punct (int ch)
{
  return ch == ','
    || ch == ':'
    || ch == '='
    || ch == '['
    || ch == ']'
    || ch == '{'
    || ch == '}'
  ;
}

constexpr bool is_bare_key_char (int it)
{
  return it == '-'
    || it == '_'
    || (it >= 'A' && it <= 'Z')
    || (it >= 'a' && it <= 'z')
    || (it >= '0' && it <= '9')
  ;

}

} // namespace

struct config_reader_t::impl_t
{
  std::istream &input;

  std::string cache{};
  std::string::const_iterator cache_it = cache.end();
  size_t line = 0;
  int it = 0;

  struct node_t
  {
    using stack_t = std::deque<node_t>;

    bool(impl_t::*context)(node_t &) = &impl_t::any;
    std::string key{};
    bool allow_comma = false;

    node_t () = default;

    node_t (bool(impl_t::*context)(node_t &))
      : context(context)
    {}

    node_t (bool(impl_t::*context)(node_t &), const std::string &key)
      : context(context)
      , key(key)
    {}

    void set (bool(impl_t::*to)(node_t &))
    {
      context = to;
    }
  };
  node_t::stack_t objects{};
  std::string current_value{};

  impl_t (std::istream &input);

  impl_t (const impl_t &) = delete;
  impl_t &operator= (const impl_t &) = delete;

  // extract option/argument
  // returns true if has more, false otherwise
  bool extract (std::string *option, std::string *argument);
  bool key_and_value (std::string *option, std::string *argument);

  // return current column number
  size_t column () const
  {
    return cache_it - cache.begin();
  }

  // read next character, caching line if necessary
  bool next ()
  {
    if (cache_it != cache.end() || load_cache())
    {
      it = *cache_it++;
    }
    else
    {
      it = 0;
    }
    return it != 0;
  }

  bool load_cache ();

  // peek at following char
  int peek () const noexcept
  {
    return *cache_it;
  }

  int unescape (int ch) const
  {
    switch (ch)
    {
      case '"': return '"';
      case '\\': return '\\';
      case 'b': return '\b';
      case 'f': return '\f';
      case 'n': return '\n';
      case 'r': return '\r';
      case 't': return '\t';
    }
    throw_unexpected("escaped character");
  }

  //
  // state handlers
  //

  bool any (node_t &node);
  bool object (node_t &node);
  bool array (node_t &node);
  bool assign (node_t &node);
  bool value (node_t &node);

  //
  // token extractors
  //

  bool skip_spaces_and_comments ();

  // different kind of extractors
  std::string extract_string (bool is_key);
  std::string extract_bare_key ();
  std::string extract_quoteless_string ();
  std::string extract_basic_string (bool allow_multiline);
  std::string extract_literal_string (bool allow_multiline);
  std::string extract_basic_multiline_string ();
  std::string extract_literal_multiline_string ();

  //
  // errors
  //

  void throw_not_supported [[noreturn]] (const char *what) const
  {
    throw_error<parser_error>(what, " is not supported ",
      '(', line, ',', column(), ')'
    );
  }

  void throw_expected [[noreturn]] (const char *what) const
  {
    throw_error<parser_error>("expected ", what, ' ',
      '(', line, ',', column(), ')'
    );
  }

  void throw_unexpected [[noreturn]] (const char *what) const
  {
    throw_error<parser_error>("unexpected ", what, ' ',
      '(', line, ',', column(), ')'
    );
  }
};

config_reader_t::config_reader_t (std::istream &input)
  : impl_(std::make_unique<impl_t>(input))
{}

config_reader_t::~config_reader_t () = default;

bool config_reader_t::operator() (const option_set_t &,
  std::string *option,
  std::string *argument)
{
  return impl_->extract(option, argument);
}

config_reader_t::impl_t::impl_t (std::istream &input)
  : input(input)
{
  objects.emplace_back();
  if (next() && skip_spaces_and_comments() && it == '{')
  {
    object(objects.back());
  }
}

bool config_reader_t::impl_t::extract (std::string *option,
  std::string *argument)
{
  while (skip_spaces_and_comments())
  {
    if (objects.empty())
    {
      throw_unexpected("end of object");
    }
    auto &node = objects.back();
    if (!(this->*node.context)(node))
    {
      return key_and_value(option, argument);
    }
  }

  while (objects.size())
  {
    const auto &node = objects.back();
    if (node.context == &impl_t::value)
    {
      return key_and_value(option, argument);
    }
    else if (node.context != &impl_t::any)
    {
      throw_unexpected("end of input");
    }
    objects.pop_back();
  }

  return false;
}

bool config_reader_t::impl_t::key_and_value (std::string *option,
  std::string *argument)
{
  std::string key;
  for (const auto &object: objects)
  {
    if (object.key.size()
      && (object.context == &impl_t::object
        || object.context == &impl_t::array
        || object.context == &impl_t::value))
    {
      key += object.key;
      key += '.';
    }
  }
  if (key.size() && key.back() == '.')
  {
    key.pop_back();
  }

  *sal_check_ptr(argument) = std::move(current_value);
  *sal_check_ptr(option) = std::move(key);

  auto &back = objects.back();
  if (back.context != &impl_t::array)
  {
    back.set(&impl_t::any);
  }
  back.allow_comma = true;
  return true;
}

bool config_reader_t::impl_t::any (node_t &node)
{
  if (it == '}')
  {
    objects.pop_back();
    return true;
  }
  else if (it == ',')
  {
    if (!node.allow_comma)
    {
      throw_unexpected("comma");
    }
    node.allow_comma = false;
  }
  else if (it == '"' || it == '\'' || is_bare_key_char(it))
  {
    node.key = extract_string(true);
    node.set(&impl_t::assign);
    return true;
  }
  else
  {
    throw_unexpected("character");
  }
  return next();
}

bool config_reader_t::impl_t::object (node_t &node)
{
  if (it == '{')
  {
    node.set(&impl_t::object);
    objects.emplace_back();
    return next();
  }
  else if (it == '}')
  {
    objects.pop_back();
    next();
    if (objects.size())
    {
      return true;
    }
  }

  objects.emplace_back();
  objects.back().allow_comma = true;
  return true;
}

bool config_reader_t::impl_t::array (node_t &node)
{
  if (it == ']')
  {
    objects.back().set(&impl_t::any);
    return next();
  }
  else if (it == ',')
  {
    if (!node.allow_comma)
    {
      throw_unexpected("comma");
    }
    node.allow_comma = false;
    return next();
  }
  else if (it == '[' || it == '{')
  {
    throw_not_supported("array of arrays or objects");
  }
  else if (is_json_punct(it))
  {
    throw_unexpected("character");
  }
  current_value = extract_string(false);
  node.allow_comma = true;
  return false;
}

bool config_reader_t::impl_t::assign (node_t &node)
{
  if (it == '=' || it == ':')
  {
    node.set(&impl_t::value);
    return next();
  }
  throw_expected("':' or '='");
}

bool config_reader_t::impl_t::value (node_t &node)
{
  if (it == '{')
  {
    node.set(&impl_t::object);
    objects.emplace_back();
    return next();
  }
  else if (it == '[')
  {
    node.set(&impl_t::array);
    return next();
  }
  current_value = extract_string(false);
  return false;
}

std::string config_reader_t::impl_t::extract_string (bool is_key)
{
  if (it == '"')
  {
    return extract_basic_string(is_key == false);
  }
  else if (it == '\'')
  {
    return extract_literal_string(is_key == false);
  }
  else
  {
    return is_key ? extract_bare_key() : extract_quoteless_string();
  }
}

std::string config_reader_t::impl_t::extract_bare_key ()
{
  std::string result;
  while (is_bare_key_char(it))
  {
    result += static_cast<char>(it);
    next();
  }

  return result;
}

std::string config_reader_t::impl_t::extract_quoteless_string ()
{
  std::string result;
  while (!is_json_punct(it) && !std::isspace(it))
  {
    if (it == '/')
    {
      auto ch = peek();
      if (ch == '/' || ch == '*')
      {
        break;
      }
    }
    result += static_cast<char>(it);
    next();
  }

  return result;
}

std::string config_reader_t::impl_t::extract_basic_string (bool allow_multiline)
{
  next();
  if (allow_multiline && it == '"' && peek() == '"')
  {
    next(), next();
    return extract_basic_multiline_string();
  }

  std::string result;
  while (it != '"')
  {
    if (it == '\n')
    {
      throw_unexpected("newline");
    }
    else if (it == '\\')
    {
      next();
      it = unescape(it);
    }
    result += static_cast<char>(it);
    next();
  }
  next();

  return result;
}

std::string config_reader_t::impl_t::extract_literal_string (bool allow_multiline)
{
  next();
  if (allow_multiline && it == '\'' && peek() == '\'')
  {
    next(), next();
    return extract_literal_multiline_string();
  }

  std::string result;
  while (it != '\'')
  {
    if (it == '\n')
    {
      throw_unexpected("newline");
    }
    result += static_cast<char>(it);
    next();
  }
  next();

  return result;
}

std::string config_reader_t::impl_t::extract_basic_multiline_string ()
{
  std::string result;

  if (it == '\n')
  {
    next();
  }

  bool skip_whitespaces = false;
  for (auto consecutive_quotes = 0U;  it && consecutive_quotes != 3;  next())
  {
    if (skip_whitespaces && std::isspace(it))
    {
      continue;
    }
    skip_whitespaces = false;

    result += static_cast<char>(it);

    if (it == '"')
    {
      ++consecutive_quotes;
      continue;
    }
    consecutive_quotes = 0;

    if (it == '\\')
    {
      next();
      if (it != '\n')
      {
        result.back() = static_cast<char>(unescape(it));
      }
      else
      {
        result.pop_back();
        skip_whitespaces = true;
      }
    }
  }

  if (it)
  {
    result.erase(result.size() - 3);
  }
  else
  {
    throw_unexpected("end of input");
  }

  return result;
}

std::string config_reader_t::impl_t::extract_literal_multiline_string ()
{
  std::string result;

  if (it == '\n')
  {
    next();
  }

  for (auto consecutive_quotes = 0U;  it && consecutive_quotes != 3;  next())
  {
    result += static_cast<char>(it);
    if (it != '\'')
    {
      consecutive_quotes = 0;
    }
    else
    {
      ++consecutive_quotes;
    }
  }

  if (it)
  {
    result.erase(result.size() - 3);
  }
  else
  {
    throw_unexpected("end of input");
  }

  return result;
}

bool config_reader_t::impl_t::load_cache ()
{
  if (!std::getline(input, cache))
  {
    return false;
  }

  while (cache.size()
    && std::isspace(static_cast<int>(cache.back())))
  {
    cache.pop_back();
  }

  line++;
  cache.push_back('\n');
  cache_it = cache.begin();

  return true;
}

bool config_reader_t::impl_t::skip_spaces_and_comments ()
{
  auto comment_recursion_depth = 0U;

  do
  {
    if (!it)
    {
      break;
    }
    else if (it == '/' && peek() == '*')
    {
      comment_recursion_depth++;
      next();
    }
    else if (it == '*' && peek() == '/')
    {
      comment_recursion_depth--;
      next();
    }
    else if (!comment_recursion_depth)
    {
      if (it == '/' && peek() == '/')
      {
        cache_it = cache.end();
      }
      else if (!std::isspace(it))
      {
        return true;
      }
    }
  } while (next());

  if (comment_recursion_depth)
  {
    throw_unexpected("end of input");
  }

  return false;
}

__sal_end
}} // namespace sal::program_options
<commit_msg>config_reader: improve next() logic to silence static analyser<commit_after>#include <sal/program_options/config_reader.hpp>
#include <sal/program_options/error.hpp>
#include <sal/assert.hpp>
#include <cctype>
#include <deque>
#include <istream>

namespace sal { namespace program_options {
__sal_begin

namespace {

constexpr bool is_json_punct (int ch)
{
  return ch == ','
    || ch == ':'
    || ch == '='
    || ch == '['
    || ch == ']'
    || ch == '{'
    || ch == '}'
  ;
}

constexpr bool is_bare_key_char (int it)
{
  return it == '-'
    || it == '_'
    || (it >= 'A' && it <= 'Z')
    || (it >= 'a' && it <= 'z')
    || (it >= '0' && it <= '9')
  ;

}

} // namespace

struct config_reader_t::impl_t
{
  std::istream &input;

  std::string cache{};
  std::string::const_iterator cache_it = cache.end();
  size_t line = 0;
  int it = 0;

  struct node_t
  {
    using stack_t = std::deque<node_t>;

    bool(impl_t::*context)(node_t &) = &impl_t::any;
    std::string key{};
    bool allow_comma = false;

    node_t () = default;

    node_t (bool(impl_t::*context)(node_t &))
      : context(context)
    {}

    node_t (bool(impl_t::*context)(node_t &), const std::string &key)
      : context(context)
      , key(key)
    {}

    void set (bool(impl_t::*to)(node_t &))
    {
      context = to;
    }
  };
  node_t::stack_t objects{};
  std::string current_value{};

  impl_t (std::istream &input);

  impl_t (const impl_t &) = delete;
  impl_t &operator= (const impl_t &) = delete;

  // extract option/argument
  // returns true if has more, false otherwise
  bool extract (std::string *option, std::string *argument);
  bool key_and_value (std::string *option, std::string *argument);

  // return current column number
  size_t column () const
  {
    return cache_it - cache.begin();
  }

  // read next character, caching line if necessary
  bool next ();
  std::string next_line ();

  // peek at following char
  int peek () const noexcept
  {
    return *cache_it;
  }

  int unescape (int ch) const
  {
    switch (ch)
    {
      case '"': return '"';
      case '\\': return '\\';
      case 'b': return '\b';
      case 'f': return '\f';
      case 'n': return '\n';
      case 'r': return '\r';
      case 't': return '\t';
    }
    throw_unexpected("escaped character");
  }

  //
  // state handlers
  //

  bool any (node_t &node);
  bool object (node_t &node);
  bool array (node_t &node);
  bool assign (node_t &node);
  bool value (node_t &node);

  //
  // token extractors
  //

  bool skip_spaces_and_comments ();

  // different kind of extractors
  std::string extract_string (bool is_key);
  std::string extract_bare_key ();
  std::string extract_quoteless_string ();
  std::string extract_basic_string (bool allow_multiline);
  std::string extract_literal_string (bool allow_multiline);
  std::string extract_basic_multiline_string ();
  std::string extract_literal_multiline_string ();

  //
  // errors
  //

  void throw_not_supported [[noreturn]] (const char *what) const
  {
    throw_error<parser_error>(what, " is not supported ",
      '(', line, ',', column(), ')'
    );
  }

  void throw_expected [[noreturn]] (const char *what) const
  {
    throw_error<parser_error>("expected ", what, ' ',
      '(', line, ',', column(), ')'
    );
  }

  void throw_unexpected [[noreturn]] (const char *what) const
  {
    throw_error<parser_error>("unexpected ", what, ' ',
      '(', line, ',', column(), ')'
    );
  }
};

config_reader_t::config_reader_t (std::istream &input)
  : impl_(std::make_unique<impl_t>(input))
{}

config_reader_t::~config_reader_t () = default;

bool config_reader_t::operator() (const option_set_t &,
  std::string *option,
  std::string *argument)
{
  return impl_->extract(option, argument);
}

config_reader_t::impl_t::impl_t (std::istream &input)
  : input(input)
{
  objects.emplace_back();
  if (next() && skip_spaces_and_comments() && it == '{')
  {
    object(objects.back());
  }
}

bool config_reader_t::impl_t::extract (std::string *option,
  std::string *argument)
{
  while (skip_spaces_and_comments())
  {
    if (objects.empty())
    {
      throw_unexpected("end of object");
    }
    auto &node = objects.back();
    if (!(this->*node.context)(node))
    {
      return key_and_value(option, argument);
    }
  }

  while (objects.size())
  {
    const auto &node = objects.back();
    if (node.context == &impl_t::value)
    {
      return key_and_value(option, argument);
    }
    else if (node.context != &impl_t::any)
    {
      throw_unexpected("end of input");
    }
    objects.pop_back();
  }

  return false;
}

bool config_reader_t::impl_t::key_and_value (std::string *option,
  std::string *argument)
{
  std::string key;
  for (const auto &object: objects)
  {
    if (object.key.size()
      && (object.context == &impl_t::object
        || object.context == &impl_t::array
        || object.context == &impl_t::value))
    {
      key += object.key;
      key += '.';
    }
  }
  if (key.size() && key.back() == '.')
  {
    key.pop_back();
  }

  *sal_check_ptr(argument) = std::move(current_value);
  *sal_check_ptr(option) = std::move(key);

  auto &back = objects.back();
  if (back.context != &impl_t::array)
  {
    back.set(&impl_t::any);
  }
  back.allow_comma = true;
  return true;
}

bool config_reader_t::impl_t::any (node_t &node)
{
  if (it == '}')
  {
    objects.pop_back();
    return true;
  }
  else if (it == ',')
  {
    if (!node.allow_comma)
    {
      throw_unexpected("comma");
    }
    node.allow_comma = false;
  }
  else if (it == '"' || it == '\'' || is_bare_key_char(it))
  {
    node.key = extract_string(true);
    node.set(&impl_t::assign);
    return true;
  }
  else
  {
    throw_unexpected("character");
  }
  return next();
}

bool config_reader_t::impl_t::object (node_t &node)
{
  if (it == '{')
  {
    node.set(&impl_t::object);
    objects.emplace_back();
    return next();
  }
  else if (it == '}')
  {
    objects.pop_back();
    next();
    if (objects.size())
    {
      return true;
    }
  }

  objects.emplace_back();
  objects.back().allow_comma = true;
  return true;
}

bool config_reader_t::impl_t::array (node_t &node)
{
  if (it == ']')
  {
    objects.back().set(&impl_t::any);
    return next();
  }
  else if (it == ',')
  {
    if (!node.allow_comma)
    {
      throw_unexpected("comma");
    }
    node.allow_comma = false;
    return next();
  }
  else if (it == '[' || it == '{')
  {
    throw_not_supported("array of arrays or objects");
  }
  else if (is_json_punct(it))
  {
    throw_unexpected("character");
  }
  current_value = extract_string(false);
  node.allow_comma = true;
  return false;
}

bool config_reader_t::impl_t::assign (node_t &node)
{
  if (it == '=' || it == ':')
  {
    node.set(&impl_t::value);
    return next();
  }
  throw_expected("':' or '='");
}

bool config_reader_t::impl_t::value (node_t &node)
{
  if (it == '{')
  {
    node.set(&impl_t::object);
    objects.emplace_back();
    return next();
  }
  else if (it == '[')
  {
    node.set(&impl_t::array);
    return next();
  }
  current_value = extract_string(false);
  return false;
}

std::string config_reader_t::impl_t::extract_string (bool is_key)
{
  if (it == '"')
  {
    return extract_basic_string(is_key == false);
  }
  else if (it == '\'')
  {
    return extract_literal_string(is_key == false);
  }
  else
  {
    return is_key ? extract_bare_key() : extract_quoteless_string();
  }
}

std::string config_reader_t::impl_t::extract_bare_key ()
{
  std::string result;
  while (is_bare_key_char(it))
  {
    result += static_cast<char>(it);
    next();
  }

  return result;
}

std::string config_reader_t::impl_t::extract_quoteless_string ()
{
  std::string result;
  while (!is_json_punct(it) && !std::isspace(it))
  {
    if (it == '/')
    {
      auto ch = peek();
      if (ch == '/' || ch == '*')
      {
        break;
      }
    }
    result += static_cast<char>(it);
    next();
  }

  return result;
}

std::string config_reader_t::impl_t::extract_basic_string (bool allow_multiline)
{
  next();
  if (allow_multiline && it == '"' && peek() == '"')
  {
    next(), next();
    return extract_basic_multiline_string();
  }

  std::string result;
  while (it != '"')
  {
    if (it == '\n')
    {
      throw_unexpected("newline");
    }
    else if (it == '\\')
    {
      next();
      it = unescape(it);
    }
    result += static_cast<char>(it);
    next();
  }
  next();

  return result;
}

std::string config_reader_t::impl_t::extract_literal_string (bool allow_multiline)
{
  next();
  if (allow_multiline && it == '\'' && peek() == '\'')
  {
    next(), next();
    return extract_literal_multiline_string();
  }

  std::string result;
  while (it != '\'')
  {
    if (it == '\n')
    {
      throw_unexpected("newline");
    }
    result += static_cast<char>(it);
    next();
  }
  next();

  return result;
}

std::string config_reader_t::impl_t::extract_basic_multiline_string ()
{
  std::string result;

  if (it == '\n')
  {
    next();
  }

  bool skip_whitespaces = false;
  for (auto consecutive_quotes = 0U;  it && consecutive_quotes != 3;  next())
  {
    if (skip_whitespaces && std::isspace(it))
    {
      continue;
    }
    skip_whitespaces = false;

    result += static_cast<char>(it);

    if (it == '"')
    {
      ++consecutive_quotes;
      continue;
    }
    consecutive_quotes = 0;

    if (it == '\\')
    {
      next();
      if (it != '\n')
      {
        result.back() = static_cast<char>(unescape(it));
      }
      else
      {
        result.pop_back();
        skip_whitespaces = true;
      }
    }
  }

  if (it)
  {
    result.erase(result.size() - 3);
  }
  else
  {
    throw_unexpected("end of input");
  }

  return result;
}

std::string config_reader_t::impl_t::extract_literal_multiline_string ()
{
  std::string result;

  if (it == '\n')
  {
    next();
  }

  for (auto consecutive_quotes = 0U;  it && consecutive_quotes != 3;  next())
  {
    result += static_cast<char>(it);
    if (it != '\'')
    {
      consecutive_quotes = 0;
    }
    else
    {
      ++consecutive_quotes;
    }
  }

  if (it)
  {
    result.erase(result.size() - 3);
  }
  else
  {
    throw_unexpected("end of input");
  }

  return result;
}

std::string config_reader_t::impl_t::next_line ()
{
  std::string result;

  if (std::getline(input, result))
  {
    while (result.size()
      && std::isspace(static_cast<int>(result.back())))
    {
      result.pop_back();
    }
    result.push_back('\n');
    line++;
  }

  return result;
}

bool config_reader_t::impl_t::next ()
{
  if (cache_it == cache.end())
  {
    cache = next_line();
    cache_it = cache.begin();
  }

  if (cache_it != cache.end())
  {
    it = *cache_it++;
  }
  else
  {
    it = 0;
  }
  return it != 0;
}

bool config_reader_t::impl_t::skip_spaces_and_comments ()
{
  auto comment_recursion_depth = 0U;

  do
  {
    if (!it)
    {
      break;
    }
    else if (it == '/' && peek() == '*')
    {
      comment_recursion_depth++;
      next();
    }
    else if (it == '*' && peek() == '/')
    {
      comment_recursion_depth--;
      next();
    }
    else if (!comment_recursion_depth)
    {
      if (it == '/' && peek() == '/')
      {
        cache_it = cache.end();
      }
      else if (!std::isspace(it))
      {
        return true;
      }
    }
  } while (next());

  if (comment_recursion_depth)
  {
    throw_unexpected("end of input");
  }

  return false;
}

__sal_end
}} // namespace sal::program_options
<|endoftext|>


<commit_before><commit_msg>make that file platform independent<commit_after><|endoftext|>


<commit_before>#ifndef MJOLNIR_INPUT_UTILITY_HPP
#define MJOLNIR_INPUT_UTILITY_HPP
#include <extlib/toml/toml.hpp>
#include <mjolnir/util/type_traits.hpp>
#include <mjolnir/util/string.hpp>
#include <mjolnir/util/logger.hpp>

namespace mjolnir
{

// This check all the keys in a table are found in a list.
//     If there is a key that is not found in the range, it warns about the
// corresponding value will be ignored.
//     In order to allow optional keys, it only checks all the keys are found
// in the specified container.
//
// Use it as the following.
// ```cpp
// check_keys_available(table, {"foo"_s, "bar"_s, "baz"_s});
// ```
inline bool check_keys_available(const toml::value& table,
                                 std::initializer_list<std::string> list)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    // no logger scope here. use the parent scope.

    bool all_available = true;
    for(const auto& kv : table.as_table())
    {
        if(list.end() == std::find(list.begin(), list.end(), kv.first))
        {
            std::ostringstream oss;
            oss << "unknown value \"" << kv.first << "\" found. this "
                << kv.second.type() << " will never be used.";
            MJOLNIR_LOG_WARN(toml::format_error(oss.str(),
                        kv.second, "this will be ignored"));
            all_available = false;
        }
    }
    return all_available;
}

template<typename T>
typename std::enable_if<negation<std::is_same<T, std::string>>::value, T>::type
find_parameter(const toml::value& params, const toml::value& env,
               const std::string& name)
{
    using ::mjolnir::literals::string_literals::operator"" _s;
    if(!params.is_table() || params.as_table().count(name) != 1)
    {
        throw std::out_of_range(toml::format_error("[error] value "_s + name +
            " does not exists"_s, params, "in this table"_s));
    }
    const toml::value& p = params.as_table().at(name);
    if(p.is_string())
    {
        // search inside of `env`
        const std::string& var = p.as_string();
        if(env.is_uninitialized())
        {
            throw std::out_of_range(toml::format_error("[error] named variable \""_s +
                var + "\" used but no env is defined"_s, params, "used here"_s));
        }
        if(!env.is_table() || env.as_table().count(var) != 1)
        {
            throw std::out_of_range(toml::format_error("[error] named variable \""_s +
                var + "\" does not exists"_s, env, "in this table"_s));
        }
        return toml::get<T>(env.as_table().at(var));
    }
    return toml::get<T>(p);
}

// If the expected value is std::string, it is difficult to distinguish
// variable name and the value itself. In that case, env would just be ignored.
template<typename T>
typename std::enable_if<std::is_same<T, std::string>::value, std::string>::type
find_parameter(const toml::value& params, const toml::value& /* env */,
               const std::string& name)
{
    if(!params.is_table() || params.as_table().count(name) != 1)
    {
        throw std::out_of_range(toml::format_error("[error] value \""_s + name +
            "\" does not exists"_s, params, "in this table"_s));
    }
    const toml::value& p = params.as_table().at(name);
    return toml::get<T>(p);
}

// The current version of Mjolnir allow to use unicode character when defining
// a parameter. But since it is a bit ambiguous because of some reasons. E.g.
// - The same character might appear in the unicode table several time with
//   different styles
// - When the different parameters appear in different names, it is ofcourse
//   ambiguous which one to be used.
//
// So I decided to deprecate them. At first I thought that a unicode names
// ware covenient to reduce the size of input file. But now, since env is
// introduced, it is more effective for reducing the file size. So if it works
// nice after the next release, I will deprecate unicode names and warn if used.
//
// This function was introduced to support those
// multi-named parameters but is planned to be removed in the later release.
template<typename T>
typename std::enable_if<negation<std::is_same<T, std::string>>::value, T>::type
find_parameter(const toml::value& params, const toml::value& env,
               const std::string& name1,  const std::string& name2)
{
    if(!params.is_table() || (params.as_table().count(name1) == 0 &&
                              params.as_table().count(name2) == 0))
    {
        throw std::out_of_range(toml::format_error("[error] value \""_s + name1 +
            "\" or \""_s + name2 + "\" does not exists"_s, params, "in this table"_s));
    }
    // name1 has priority.
    const toml::value& p = (params.as_table().count(name1) == 1) ?
                            params.as_table().at(name1)          :
                            params.as_table().at(name2)          ;
    if(p.is_string())
    {
        // search inside of `env`
        const std::string& var = p.as_string();
        if(env.is_uninitialized())
        {
            throw std::out_of_range(toml::format_error("[error] named variable \""_s +
                var + "\" used but no env is defined"_s, params, "used here"_s));
        }
        if(!env.is_table() || env.as_table().count(var) != 1)
        {
            throw std::out_of_range(toml::format_error("[error] named variable \""_s +
                var + "\" does not exists"_s, env, "in this table"_s));
        }
        return toml::get<T>(env.as_table().at(var));
    }
    return toml::get<T>(p);
}

} // mjolnir
#endif// MJOLNIR_INPUT_UTILITY_HPP
<commit_msg>art: remove [error] prefix inserted by toml11<commit_after>#ifndef MJOLNIR_INPUT_UTILITY_HPP
#define MJOLNIR_INPUT_UTILITY_HPP
#include <extlib/toml/toml.hpp>
#include <mjolnir/util/type_traits.hpp>
#include <mjolnir/util/string.hpp>
#include <mjolnir/util/logger.hpp>

namespace mjolnir
{

// This check all the keys in a table are found in a list.
//     If there is a key that is not found in the range, it warns about the
// corresponding value will be ignored.
//     In order to allow optional keys, it only checks all the keys are found
// in the specified container.
//
// Use it as the following.
// ```cpp
// check_keys_available(table, {"foo"_s, "bar"_s, "baz"_s});
// ```
inline bool check_keys_available(const toml::value& table,
                                 std::initializer_list<std::string> list)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    // no logger scope here. use the parent scope.

    bool all_available = true;
    for(const auto& kv : table.as_table())
    {
        if(list.end() == std::find(list.begin(), list.end(), kv.first))
        {
            std::ostringstream oss;
            oss << "unknown value \"" << kv.first << "\" found. this "
                << kv.second.type() << " will never be used.";
            const auto err_msg = toml::format_error(
                    oss.str(), kv.second, "this will be ignored");
            // workaround to skip auto-added [error].
            // Normally this function is called only when the input file
            // contains an invalid key. So it should not be a hotspot.
            MJOLNIR_LOG_WARN(err_msg.substr(err_msg.find(oss.str())));
            all_available = false;
        }
    }
    return all_available;
}

template<typename T>
typename std::enable_if<negation<std::is_same<T, std::string>>::value, T>::type
find_parameter(const toml::value& params, const toml::value& env,
               const std::string& name)
{
    using ::mjolnir::literals::string_literals::operator"" _s;
    if(!params.is_table() || params.as_table().count(name) != 1)
    {
        throw std::out_of_range(toml::format_error("[error] value "_s + name +
            " does not exists"_s, params, "in this table"_s));
    }
    const toml::value& p = params.as_table().at(name);
    if(p.is_string())
    {
        // search inside of `env`
        const std::string& var = p.as_string();
        if(env.is_uninitialized())
        {
            throw std::out_of_range(toml::format_error("[error] named variable \""_s +
                var + "\" used but no env is defined"_s, params, "used here"_s));
        }
        if(!env.is_table() || env.as_table().count(var) != 1)
        {
            throw std::out_of_range(toml::format_error("[error] named variable \""_s +
                var + "\" does not exists"_s, env, "in this table"_s));
        }
        return toml::get<T>(env.as_table().at(var));
    }
    return toml::get<T>(p);
}

// If the expected value is std::string, it is difficult to distinguish
// variable name and the value itself. In that case, env would just be ignored.
template<typename T>
typename std::enable_if<std::is_same<T, std::string>::value, std::string>::type
find_parameter(const toml::value& params, const toml::value& /* env */,
               const std::string& name)
{
    if(!params.is_table() || params.as_table().count(name) != 1)
    {
        throw std::out_of_range(toml::format_error("[error] value \""_s + name +
            "\" does not exists"_s, params, "in this table"_s));
    }
    const toml::value& p = params.as_table().at(name);
    return toml::get<T>(p);
}

// The current version of Mjolnir allow to use unicode character when defining
// a parameter. But since it is a bit ambiguous because of some reasons. E.g.
// - The same character might appear in the unicode table several time with
//   different styles
// - When the different parameters appear in different names, it is ofcourse
//   ambiguous which one to be used.
//
// So I decided to deprecate them. At first I thought that a unicode names
// ware covenient to reduce the size of input file. But now, since env is
// introduced, it is more effective for reducing the file size. So if it works
// nice after the next release, I will deprecate unicode names and warn if used.
//
// This function was introduced to support those
// multi-named parameters but is planned to be removed in the later release.
template<typename T>
typename std::enable_if<negation<std::is_same<T, std::string>>::value, T>::type
find_parameter(const toml::value& params, const toml::value& env,
               const std::string& name1,  const std::string& name2)
{
    if(!params.is_table() || (params.as_table().count(name1) == 0 &&
                              params.as_table().count(name2) == 0))
    {
        throw std::out_of_range(toml::format_error("[error] value \""_s + name1 +
            "\" or \""_s + name2 + "\" does not exists"_s, params, "in this table"_s));
    }
    // name1 has priority.
    const toml::value& p = (params.as_table().count(name1) == 1) ?
                            params.as_table().at(name1)          :
                            params.as_table().at(name2)          ;
    if(p.is_string())
    {
        // search inside of `env`
        const std::string& var = p.as_string();
        if(env.is_uninitialized())
        {
            throw std::out_of_range(toml::format_error("[error] named variable \""_s +
                var + "\" used but no env is defined"_s, params, "used here"_s));
        }
        if(!env.is_table() || env.as_table().count(var) != 1)
        {
            throw std::out_of_range(toml::format_error("[error] named variable \""_s +
                var + "\" does not exists"_s, env, "in this table"_s));
        }
        return toml::get<T>(env.as_table().at(var));
    }
    return toml::get<T>(p);
}

} // mjolnir
#endif// MJOLNIR_INPUT_UTILITY_HPP
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2006 by Till Adam <adam@kde.org>                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include <QDebug>
#include <QEventLoop>

#include "akonadiconnection.h"
#include "handler.h"
#include "response.h"

using namespace Akonadi;

AkonadiConnection::AkonadiConnection( int socketDescriptor, QObject *parent )
    : QThread(parent)
    , m_socketDescriptor(socketDescriptor)
    , m_tcpSocket( 0 )
    , m_currentHandler( 0 )
    , m_connectionState( NonAuthenticated )
{
}

AkonadiConnection::~AkonadiConnection()
{
    qDebug() << "Connection closed";
    delete m_tcpSocket;
}

void AkonadiConnection::run()
{
    m_tcpSocket = new QTcpSocket();

    if ( !m_tcpSocket->setSocketDescriptor( m_socketDescriptor ) ) {
        emit error(m_tcpSocket->error());
        return;
    }

    writeOut( "* OK Akonadi Almost IMAP Server");

    /* Start a local event loop and start processing incoming data. Whenever
     * a full command has been read, it is delegated to the responsible
     * handler and processed by that. If that command needs to do something
     * asynchronous such as ask the db for data, it returns and the input
     * queue can continue to be processed. Whenever there is something to
     * be sent back to the user it is queued in the form of a Response object.
     * All this is meant to make it possible to process large incoming or
     * outgoing data transfers in a streaming manner, without having to
     * hold them in memory 'en gros'. */

    connect( m_tcpSocket, SIGNAL( readyRead() ),
             this, SLOT( slotNewData() ) );
    connect( m_tcpSocket, SIGNAL( disconnected() ),
             this, SLOT( slotDisconnected() ) );
    exec();
}

void AkonadiConnection::slotDisconnected()
{
    quit();
}

void AkonadiConnection::slotNewData()
{
    QByteArray line = m_tcpSocket->readLine().trimmed();
    qDebug() << "GOT:" << line << endl;
    if ( !m_currentHandler ) {
        // this is a new command, which means the line must start with a tag
        // followed by a non-empty command. First get the tag
        int separator = line.indexOf(' ');
        if ( separator == -1 || separator == line.size() ) {
            writeOut( "* BAD Untagged client command cannot be processed" );
            return;
        }
        // parse our the tag
        const QByteArray tag = line.left( separator );
        // and the command
        int commandStart = line.indexOf( ' ', 0 ) + 1;
        int commandEnd = line.indexOf( ' ', commandStart );
        if ( commandEnd == -1 ) commandEnd = line.size();
        const QByteArray command = line.mid( commandStart, commandEnd - commandStart ).toUpper();

        m_currentHandler = findHandlerForCommand( command );
        m_currentHandler->setTag( tag );
        assert( m_currentHandler );
        connect( m_currentHandler, SIGNAL( responseAvailable( const Response & ) ),
                 this, SLOT( slotResponseAvailable( const Response & ) ) );
        connect( m_currentHandler, SIGNAL( connectionStateChange( ConnectionState ) ),
                 this, SLOT( slotConnectionStateChange( ConnectionState ) ) );
    }
    if ( m_currentHandler->handleLine( line ) )
        m_currentHandler = 0;
}

void AkonadiConnection::writeOut( const char* str )
{
    qDebug() << "writing out: " << str << endl;
    QByteArray block;
    QTextStream out(&block, QIODevice::WriteOnly);
    out << str << endl;
    out.flush();
    m_tcpSocket->write(block);
    m_tcpSocket->waitForBytesWritten();
}

Handler * AkonadiConnection::findHandlerForCommand( const QByteArray & command )
{
    Handler * handler = Handler::findHandlerForCommandAlwaysAllowed( command );
    if ( handler ) return handler;

    switch ( m_connectionState ) {
        case NonAuthenticated:
            handler =  Handler::findHandlerForCommandNonAuthenticated( command );            break;
        case Authenticated:
            handler =  Handler::findHandlerForCommandAuthenticated( command );
            break;
        case Selected:
            break;
        case LoggingOut:
            break;
    }
    // we didn't have a handler for this, let the default one do its thing
    if ( !handler ) handler = new Handler();
    return handler;
}

void AkonadiConnection::slotResponseAvailable( const Response& response )
{
    // FIXME handle reentrancy in the presence of continuation. Something like:
    // "if continuation pending, queue responses, once continuation is done, replay them"
    writeOut( response.asString().data() );
}

void AkonadiConnection::slotConnectionStateChange( ConnectionState state )
{
    if ( state == m_connectionState ) return;
    m_connectionState = state;
    switch ( m_connectionState ) {
        case NonAuthenticated:
            assert( 0 ); // can't happen, it's only the initial state, we can't go back to it
            break;
        case Authenticated:
            break;
        case Selected:
            break;
        case LoggingOut:
            m_tcpSocket->disconnectFromHost();
            break;
    }
}
<commit_msg>build<commit_after>/***************************************************************************
 *   Copyright (C) 2006 by Till Adam <adam@kde.org>                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include <QDebug>
#include <QEventLoop>

#include "akonadiconnection.h"
#include "handler.h"
#include "response.h"

#include <assert.h>

using namespace Akonadi;

AkonadiConnection::AkonadiConnection( int socketDescriptor, QObject *parent )
    : QThread(parent)
    , m_socketDescriptor(socketDescriptor)
    , m_tcpSocket( 0 )
    , m_currentHandler( 0 )
    , m_connectionState( NonAuthenticated )
{
}

AkonadiConnection::~AkonadiConnection()
{
    qDebug() << "Connection closed";
    delete m_tcpSocket;
}

void AkonadiConnection::run()
{
    m_tcpSocket = new QTcpSocket();

    if ( !m_tcpSocket->setSocketDescriptor( m_socketDescriptor ) ) {
        emit error(m_tcpSocket->error());
        return;
    }

    writeOut( "* OK Akonadi Almost IMAP Server");

    /* Start a local event loop and start processing incoming data. Whenever
     * a full command has been read, it is delegated to the responsible
     * handler and processed by that. If that command needs to do something
     * asynchronous such as ask the db for data, it returns and the input
     * queue can continue to be processed. Whenever there is something to
     * be sent back to the user it is queued in the form of a Response object.
     * All this is meant to make it possible to process large incoming or
     * outgoing data transfers in a streaming manner, without having to
     * hold them in memory 'en gros'. */

    connect( m_tcpSocket, SIGNAL( readyRead() ),
             this, SLOT( slotNewData() ) );
    connect( m_tcpSocket, SIGNAL( disconnected() ),
             this, SLOT( slotDisconnected() ) );
    exec();
}

void AkonadiConnection::slotDisconnected()
{
    quit();
}

void AkonadiConnection::slotNewData()
{
    QByteArray line = m_tcpSocket->readLine().trimmed();
    qDebug() << "GOT:" << line << endl;
    if ( !m_currentHandler ) {
        // this is a new command, which means the line must start with a tag
        // followed by a non-empty command. First get the tag
        int separator = line.indexOf(' ');
        if ( separator == -1 || separator == line.size() ) {
            writeOut( "* BAD Untagged client command cannot be processed" );
            return;
        }
        // parse our the tag
        const QByteArray tag = line.left( separator );
        // and the command
        int commandStart = line.indexOf( ' ', 0 ) + 1;
        int commandEnd = line.indexOf( ' ', commandStart );
        if ( commandEnd == -1 ) commandEnd = line.size();
        const QByteArray command = line.mid( commandStart, commandEnd - commandStart ).toUpper();

        m_currentHandler = findHandlerForCommand( command );
        m_currentHandler->setTag( tag );
        assert( m_currentHandler );
        connect( m_currentHandler, SIGNAL( responseAvailable( const Response & ) ),
                 this, SLOT( slotResponseAvailable( const Response & ) ) );
        connect( m_currentHandler, SIGNAL( connectionStateChange( ConnectionState ) ),
                 this, SLOT( slotConnectionStateChange( ConnectionState ) ) );
    }
    if ( m_currentHandler->handleLine( line ) )
        m_currentHandler = 0;
}

void AkonadiConnection::writeOut( const char* str )
{
    qDebug() << "writing out: " << str << endl;
    QByteArray block;
    QTextStream out(&block, QIODevice::WriteOnly);
    out << str << endl;
    out.flush();
    m_tcpSocket->write(block);
    m_tcpSocket->waitForBytesWritten();
}

Handler * AkonadiConnection::findHandlerForCommand( const QByteArray & command )
{
    Handler * handler = Handler::findHandlerForCommandAlwaysAllowed( command );
    if ( handler ) return handler;

    switch ( m_connectionState ) {
        case NonAuthenticated:
            handler =  Handler::findHandlerForCommandNonAuthenticated( command );            break;
        case Authenticated:
            handler =  Handler::findHandlerForCommandAuthenticated( command );
            break;
        case Selected:
            break;
        case LoggingOut:
            break;
    }
    // we didn't have a handler for this, let the default one do its thing
    if ( !handler ) handler = new Handler();
    return handler;
}

void AkonadiConnection::slotResponseAvailable( const Response& response )
{
    // FIXME handle reentrancy in the presence of continuation. Something like:
    // "if continuation pending, queue responses, once continuation is done, replay them"
    writeOut( response.asString().data() );
}

void AkonadiConnection::slotConnectionStateChange( ConnectionState state )
{
    if ( state == m_connectionState ) return;
    m_connectionState = state;
    switch ( m_connectionState ) {
        case NonAuthenticated:
            assert( 0 ); // can't happen, it's only the initial state, we can't go back to it
            break;
        case Authenticated:
            break;
        case Selected:
            break;
        case LoggingOut:
            m_tcpSocket->disconnectFromHost();
            break;
    }
}
<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "alsadeviceenumerator.h"
#include "alsadeviceenumerator_p.h"
#include "alsadevice_p.h"
#include <kdebug.h>
#include <alsa/asoundlib.h>
#include <QDir>
#include <solid/devicemanager.h>
#include <solid/device.h>
#include <solid/audiohw.h>

namespace Phonon
{

AlsaDeviceEnumerator *AlsaDeviceEnumerator::s_instance = 0;

AlsaDeviceEnumerator *AlsaDeviceEnumerator::self()
{
    if (!s_instance) {
        s_instance = new AlsaDeviceEnumerator;
        s_instance->d->findDevices();
    }
    return s_instance;
}

AlsaDevice *AlsaDeviceEnumerator::deviceFor(const QString &internalId)
{
    for (int i = 0; i < d->devicelist.size(); ++i) {
        if (d->devicelist[i].d->internalId == internalId) {
            return &d->devicelist[i];
        }
    }
    return 0;
}

AlsaDeviceEnumerator::AlsaDeviceEnumerator(QObject *parent)
    : QObject(parent),
    d(new AlsaDeviceEnumeratorPrivate)
{
}

void AlsaDeviceEnumeratorPrivate::findDevices()
{
    // first check the 'default' device and the devices defined in ~/.asoundrc and /etc/asound.conf
    AlsaDevice defaultCtlDevice(QLatin1String("default"), AlsaDevice::ControlAndPcm);
    if (defaultCtlDevice.isValid()) {
        devicelist << defaultCtlDevice;
    }
    findAsoundrcDevices(QDir::homePath() + "/.asoundrc");
    findAsoundrcDevices("/etc/asound.conf");

    // then ask Solid for the available audio hardware
    Solid::DeviceManager &manager = Solid::DeviceManager::self();

    Solid::DeviceList devices = manager.findDevicesFromQuery(QString(), Solid::Capability::AudioHw,
            Solid::Predicate(Solid::Capability::AudioHw, QLatin1String("driver"), Solid::AudioHw::Alsa));
    foreach (Solid::Device device, devices) {
        Solid::AudioHw *audiohw = device.as<Solid::AudioHw>();
        Q_ASSERT(audiohw);
        Q_ASSERT(audiohw->driver() == Solid::AudioHw::Alsa);
        QString handle = audiohw->driverHandler();
        kDebug(603) << k_funcinfo << handle << ", " << audiohw->name() << ", " << audiohw->driver() << ", " << audiohw->type() << endl;
        if (audiohw->type() & Solid::AudioHw::AudioOutput) {
            handle = handle.right(handle.size() - handle.indexOf(':') - 1);
            int comma = handle.indexOf(',');
            int devicenum = -1;
            if (comma > -1) {
                //devicenum = handle.right(handle.size() - 1 - comma).toInt();
                handle = handle.left(comma);
            }
            AlsaDevice dev(handle.toInt(), devicenum);
            if (dev.isValid()) {
                devicelist << dev;
            }
        }
    }

    // look at the list of currently available devices
    /*int card = -1;
    while (snd_card_next(&card) >= 0 && card >= 0) {
        AlsaDevice dev(card);
        if (dev.isValid()) {
            devicelist << dev;
        }
    }*/

    // TODO register with Solid to emit the devicePlugged/deviceUnplugged signals
}

void AlsaDeviceEnumeratorPrivate::findAsoundrcDevices(const QString &fileName)
{
    QFile asoundrcFile(fileName);
    asoundrcFile.open(QIODevice::ReadOnly);
    QTextStream asoundrcStream(&asoundrcFile);
    QString line;
    QStringList words;
    int depth = 0;
    while (!asoundrcStream.atEnd()) {
        line = asoundrcStream.readLine().simplified();
        //kDebug(603) << "'" << line << "'" << endl;
        if (line.startsWith('#')) {
            continue; //skip comment lines
        }
        if (line.contains('#')) { // truncate comments at the end of the line
            line = line.left(line.indexOf('#'));
            //kDebug(603) << "'" << line << "'" << endl;
        }
        words = line.split(' ', QString::SkipEmptyParts);
        foreach (QString word, words) {
            if (word == QLatin1String("{")) {
                ++depth;
            } else if (word == QLatin1String("}")) {
                --depth;
            } else if (depth == 0) {
                int index = word.indexOf('.');
                if (index != -1) {
                    QString type = word.left(index).toLower();
                    if (type == QLatin1String("ctl")) {
                        QString deviceName = word.right(word.size() - index - 1);
                        if (deviceName.startsWith('!')) {
                            deviceName = deviceName.right(deviceName.size() - 1);
                        }
                        AlsaDevice dev(deviceName, AlsaDevice::Control);
                        if (dev.isValid()) {
                            devicelist << dev;
                        }
                    } else if (type == QLatin1String("pcm")) {
                        QString deviceName = word.right(word.size() - index - 1);
                        if (deviceName.startsWith('!')) {
                            deviceName = deviceName.right(deviceName.size() - 1);
                        }
                        AlsaDevice dev(deviceName, AlsaDevice::Pcm);
                        if (dev.isValid()) {
                            devicelist << dev;
                        }
                    }
                }
            }
        }
    }
}

AlsaDeviceEnumerator::~AlsaDeviceEnumerator()
{
    delete d;
    d = 0;
}

QList<AlsaDevice> AlsaDeviceEnumerator::availableDevices()
{
    return self()->d->devicelist;
}

} // namespace Phonon
#include "alsadeviceenumerator.moc"

// vim: sw=4 sts=4 et tw=100
<commit_msg>QString deviceHandle -> QStringList deviceHandles (only on the frontend, the frontend can now add logic for a preference of device handles for the same device (needed for ALSA)<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "alsadeviceenumerator.h"
#include "alsadeviceenumerator_p.h"
#include "alsadevice_p.h"
#include <kdebug.h>
#include <alsa/asoundlib.h>
#include <QDir>
#include <solid/devicemanager.h>
#include <solid/device.h>
#include <solid/audiohw.h>

namespace Phonon
{

AlsaDeviceEnumerator *AlsaDeviceEnumerator::s_instance = 0;

AlsaDeviceEnumerator *AlsaDeviceEnumerator::self()
{
    if (!s_instance) {
        s_instance = new AlsaDeviceEnumerator;
        s_instance->d->findDevices();
    }
    return s_instance;
}

AlsaDevice *AlsaDeviceEnumerator::deviceFor(const QString &internalId)
{
    for (int i = 0; i < d->devicelist.size(); ++i) {
        if (d->devicelist[i].d->internalId == internalId) {
            return &d->devicelist[i];
        }
    }
    return 0;
}

AlsaDeviceEnumerator::AlsaDeviceEnumerator(QObject *parent)
    : QObject(parent),
    d(new AlsaDeviceEnumeratorPrivate)
{
}

void AlsaDeviceEnumeratorPrivate::findDevices()
{
    // first check the 'default' device and the devices defined in ~/.asoundrc and /etc/asound.conf
    AlsaDevice defaultCtlDevice(QLatin1String("default"), AlsaDevice::ControlAndPcm);
    if (defaultCtlDevice.isValid()) {
        devicelist << defaultCtlDevice;
    }
    findAsoundrcDevices(QDir::homePath() + "/.asoundrc");
    findAsoundrcDevices("/etc/asound.conf");

    // then ask Solid for the available audio hardware
    Solid::DeviceManager &manager = Solid::DeviceManager::self();

    Solid::DeviceList devices = manager.findDevicesFromQuery(QString(), Solid::Capability::AudioHw,
            Solid::Predicate(Solid::Capability::AudioHw, QLatin1String("driver"), Solid::AudioHw::Alsa));
    foreach (Solid::Device device, devices) {
        Solid::AudioHw *audiohw = device.as<Solid::AudioHw>();
        Q_ASSERT(audiohw);
        Q_ASSERT(audiohw->driver() == Solid::AudioHw::Alsa);
        QStringList handles = audiohw->driverHandles();
        kDebug(603) << k_funcinfo << handles << ", " << audiohw->name() << ", " << audiohw->driver() << ", " << audiohw->deviceType() << endl;
        if (audiohw->deviceType() & Solid::AudioHw::AudioOutput) {
            QString handle = handles.last();
            handle = handle.right(handle.size() - handle.indexOf(':') - 1);
            int comma = handle.indexOf(',');
            int devicenum = -1;
            if (comma > -1) {
                //devicenum = handle.right(handle.size() - 1 - comma).toInt();
                handle = handle.left(comma);
            }
            AlsaDevice dev(handle.toInt(), devicenum);
            if (dev.isValid()) {
                devicelist << dev;
            }
        }
    }

    // look at the list of currently available devices
    /*int card = -1;
    while (snd_card_next(&card) >= 0 && card >= 0) {
        AlsaDevice dev(card);
        if (dev.isValid()) {
            devicelist << dev;
        }
    }*/

    // TODO register with Solid to emit the devicePlugged/deviceUnplugged signals
}

void AlsaDeviceEnumeratorPrivate::findAsoundrcDevices(const QString &fileName)
{
    QFile asoundrcFile(fileName);
    asoundrcFile.open(QIODevice::ReadOnly);
    QTextStream asoundrcStream(&asoundrcFile);
    QString line;
    QStringList words;
    int depth = 0;
    while (!asoundrcStream.atEnd()) {
        line = asoundrcStream.readLine().simplified();
        //kDebug(603) << "'" << line << "'" << endl;
        if (line.startsWith('#')) {
            continue; //skip comment lines
        }
        if (line.contains('#')) { // truncate comments at the end of the line
            line = line.left(line.indexOf('#'));
            //kDebug(603) << "'" << line << "'" << endl;
        }
        words = line.split(' ', QString::SkipEmptyParts);
        foreach (QString word, words) {
            if (word == QLatin1String("{")) {
                ++depth;
            } else if (word == QLatin1String("}")) {
                --depth;
            } else if (depth == 0) {
                int index = word.indexOf('.');
                if (index != -1) {
                    QString type = word.left(index).toLower();
                    if (type == QLatin1String("ctl")) {
                        QString deviceName = word.right(word.size() - index - 1);
                        if (deviceName.startsWith('!')) {
                            deviceName = deviceName.right(deviceName.size() - 1);
                        }
                        AlsaDevice dev(deviceName, AlsaDevice::Control);
                        if (dev.isValid()) {
                            devicelist << dev;
                        }
                    } else if (type == QLatin1String("pcm")) {
                        QString deviceName = word.right(word.size() - index - 1);
                        if (deviceName.startsWith('!')) {
                            deviceName = deviceName.right(deviceName.size() - 1);
                        }
                        AlsaDevice dev(deviceName, AlsaDevice::Pcm);
                        if (dev.isValid()) {
                            devicelist << dev;
                        }
                    }
                }
            }
        }
    }
}

AlsaDeviceEnumerator::~AlsaDeviceEnumerator()
{
    delete d;
    d = 0;
}

QList<AlsaDevice> AlsaDeviceEnumerator::availableDevices()
{
    return self()->d->devicelist;
}

} // namespace Phonon
#include "alsadeviceenumerator.moc"

// vim: sw=4 sts=4 et tw=100
<|endoftext|>


<commit_before>/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
/**
 * @author Dmitriy S. Matveev, Viskov Nikolay
 * @version $Revision$
 */
#include "Font.h"
#include "Environment.h"
#include "TTFont.h"
#include "T1Font.h"
#include <string.h>

Font::Font() {
    _famName = NULL;
}

Font::~Font() {
	for( std::map<const uflong, Glyph*>::iterator iter = _glyphMap.begin(); iter != _glyphMap.end(); iter++ ) {
		delete iter->second;
	}

	delete[] _famName;

	/*ufshort famLength = fwcslen((fwchar_t *)_famName);
	fchar *family = new fchar[famLength+1];

	ufshort i;
	for (i = 0;i < famLength;i++) {
		(family)[i] = _famName[i];
	}
	(family)[i] = '\0';

	FontHeader* fh = GraphicsEnvironment::getAllFonts()->_head;
	//printf("\nfaund = -%s-\n", family);
	for(fint i=0; i<GraphicsEnvironment::_length; i++){
		//printf("font = -%s-\n", fh->_familyName);
		if (strcmp(fh->_familyName,family)==0 && fh->_style == _style) {
			fh->_font = NULL;
			break;
		}

		fh=fh->_nextHeader;
	}

	delete[] family;*/
}

Glyph* Font::createGlyph(ufshort unicode, ufshort size){
	return NULL;
}

fwchar_t* Font::getPSName()
{
	return NULL;
}

ffloat* Font::getLineMetrics()
{
	return NULL;
}

fint	Font::getMissingGlyphCode()
{
	return 0;
}

bool Font::canDisplay(ufshort c)
{
	return 0;
}

ufshort Font::getUnicodeByIndex(ufshort ind)
{
	return 0;
}

//unicode = 0 - default glyph
Glyph* Font::getGlyph(ufshort unicode, ufshort size) {
	uflong id;

	//printf("unicode = %lu, size = %lu\n", unicode,size);

    if (!canDisplay(unicode)) {
		id = (uflong)(size << 16);
        unicode = 0;
    } else {
		id = (uflong)(size << 16) + unicode;
    }

    //printf("unicode = %lu, size = %lu, id = %lu\n", unicode,size,id);

	std::map<const uflong, Glyph*>::iterator iter = _glyphMap.find(id);
	if (iter != _glyphMap.end()) {
//printf("return the glyph");
		return (Glyph *)(*iter).second;
	}
//printf("creation of the glyph");
	Glyph *glyph = createGlyph(unicode, size);

	_glyphMap[id] = glyph;

	return glyph;
}

// Creation of font depending on font type
Font* createFont(fchar* family, StyleName sn) {
	fint nLen = (fint) strlen(family);
	fwchar_t* name = new fwchar_t[nLen+1];
	for (fint i = 0; i <= nLen; i++)
		name[i] = family[i];

	Font* retFont = createFont(name, sn);

	delete[] name;

	return retFont;
}

// Creation of font depending on font type
Font* createFont(fwchar_t* family, StyleName sn)
{
	Font* retFont;
	bool isFound = false;

	if (Environment::getAllFonts() == NULL)	return NULL;

	for(FontHeader* fh = Environment::getAllFonts();
		fh != NULL; fh=fh->_nextHeader)
	{

		if (fwcscmp(fh->_familyName,family)==0 && fh->_style == sn)
		{

			switch(fh->_fType)
			{
				case TrueType:
						retFont = new TTFont(fh->_filePath);
						fh->_font=retFont;

					break;
				case Type1:
						retFont = new T1Font(family,sn,fh->_filePath);
						fh->_font=retFont;

					break;
			}
			isFound = true;
			break;
		}
	}
	if (!isFound)
	{
//		printf("Font not found");
		return 0; //
	}
	return retFont;
}
<commit_msg>Fix for HARMONY-6033 ([classlib][awt] - remove unrecognized char in file Font.cpp)<commit_after>/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
/**
 * @author Dmitriy S. Matveev, Viskov Nikolay
 * @version $Revision$
 */
#include "Font.h"
#include "Environment.h"
#include "TTFont.h"
#include "T1Font.h"
#include <string.h>

Font::Font() {
    _famName = NULL;
}

Font::~Font() {
	for( std::map<const uflong, Glyph*>::iterator iter = _glyphMap.begin(); iter != _glyphMap.end(); iter++ ) {
		delete iter->second;
	}

	delete[] _famName;

	/*ufshort famLength = fwcslen((fwchar_t *)_famName);
	fchar *family = new fchar[famLength+1];

	ufshort i;
	for (i = 0;i < famLength;i++) {
		(family)[i] = _famName[i];
	}
	(family)[i] = '\0';

	FontHeader* fh = GraphicsEnvironment::getAllFonts()->_head;
	//printf("\nfaund = -%s-\n", family);
	for(fint i=0; i<GraphicsEnvironment::_length; i++){
		//printf("font = -%s-\n", fh->_familyName);
		if (strcmp(fh->_familyName,family)==0 && fh->_style == _style) {
			fh->_font = NULL;
			break;
		}

		fh=fh->_nextHeader;
	}

	delete[] family;*/
}

Glyph* Font::createGlyph(ufshort unicode, ufshort size){
	return NULL;
}

fwchar_t* Font::getPSName()
{
	return NULL;
}

ffloat* Font::getLineMetrics()
{
	return NULL;
}

fint	Font::getMissingGlyphCode()
{
	return 0;
}

bool Font::canDisplay(ufshort c)
{
	return 0;
}

ufshort Font::getUnicodeByIndex(ufshort ind)
{
	return 0;
}

//unicode = 0 - default glyph
Glyph* Font::getGlyph(ufshort unicode, ufshort size) {
	uflong id;

	//printf("unicode = %lu, size = %lu\n", unicode,size);

    if (!canDisplay(unicode)) {
		id = (uflong)(size << 16);
        unicode = 0;
    } else {
		id = (uflong)(size << 16) + unicode;
    }

    //printf("unicode = %lu, size = %lu, id = %lu\n", unicode,size,id);

	std::map<const uflong, Glyph*>::iterator iter = _glyphMap.find(id);
	if (iter != _glyphMap.end()) {
//printf("return the glyph");
		return (Glyph *)(*iter).second;
	}
//printf("creation of the glyph");
	Glyph *glyph = createGlyph(unicode, size);

	_glyphMap[id] = glyph;

	return glyph;
}

// Creation of font depending on font type
Font* createFont(fchar* family, StyleName sn) {
	fint nLen = (fint) strlen(family);
	fwchar_t* name = new fwchar_t[nLen+1];
	for (fint i = 0; i <= nLen; i++)
		name[i] = family[i];

	Font* retFont = createFont(name, sn);

	delete[] name;

	return retFont;
}

// Creation of font depending on font type
Font* createFont(fwchar_t* family, StyleName sn)
{
	Font* retFont;
	bool isFound = false;

	if (Environment::getAllFonts() == NULL)	return NULL;

	for(FontHeader* fh = Environment::getAllFonts();
		fh != NULL; fh=fh->_nextHeader)
	{

		if (fwcscmp(fh->_familyName,family)==0 && fh->_style == sn)
		{

			switch(fh->_fType)
			{
				case TrueType:
						retFont = new TTFont(fh->_filePath);
						fh->_font=retFont;

					break;
				case Type1:
						retFont = new T1Font(family,sn,fh->_filePath);
						fh->_font=retFont;

					break;
			}
			isFound = true;
			break;
		}
	}
	if (!isFound)
	{
//		printf("Font not found");
		return 0; //Font not found
	}
	return retFont;
}
<|endoftext|>


<commit_before><commit_msg>add missing file<commit_after><|endoftext|>


<commit_before>/*
 * Copyright © 2012, United States Government, as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All rights reserved.
 *
 * The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is licensed
 * under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
*/

/**
 * @file MuscleNP.cpp
 * @brief Definition of a massless cable with contact dynamics
 * $Id$
 */

// This object
#include "MuscleNP.h"

// NTRT
#include "tgcreator/tgUtil.h"
#include "core/muscleAnchor.h"
#include "core/tgCast.h"
#include "core/tgBulletUtil.h"
#include "core/tgWorld.h"
// The Bullet Physics library
#include "btBulletDynamicsCommon.h"
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
#include "BulletCollision/BroadphaseCollision/btDispatcher.h"
#include "BulletDynamics/Dynamics/btDynamicsWorld.h"
#include "BulletDynamics/Dynamics/btActionInterface.h"
#include "LinearMath/btDefaultMotionState.h"
#include "LinearMath/btQuaternion.h"

// The C++ Standard Library
#include <iostream>
#include <algorithm>    // std::sort

MuscleNP::MuscleNP(btPairCachingGhostObject* ghostObject,
 tgWorld& world,
 btRigidBody * body1,
 btVector3 pos1,
 btRigidBody * body2,
 btVector3 pos2,
 double coefK,
 double dampingCoefficient) :
Muscle2P (body1, pos1, body2, pos2, coefK, dampingCoefficient),
m_ghostObject(ghostObject),
m_overlappingPairCache(tgBulletUtil::worldToDynamicsWorld(world).getBroadphase()),
m_dispatcher(tgBulletUtil::worldToDynamicsWorld(world).getDispatcher()),
m_ac(anchor1, anchor2)
{

}

MuscleNP::~MuscleNP()
{

}

const btScalar MuscleNP::getActualLength() const
{
    btScalar length = 0;

    std::size_t n = m_anchors.size() - 1;
    for (std::size_t i = 0; i < n; i++)
    {
        length += (m_anchors[i]->getWorldPosition() - m_anchors[i+1]->getWorldPosition()).length();
    }

    return length;
}

btVector3 MuscleNP::calculateAndApplyForce(double dt)
{

	updateAnchorList(dt);

    // Apply forces

    updateCollisionObject();
}

void MuscleNP::updateAnchorList(double dt)
{
	std::vector<const muscleAnchor*>::iterator it = m_anchors.begin();
    muscleAnchor* temp;
	for (it = m_anchors.begin(); it != m_anchors.end(); it++)
	{
		if ((*it)->permanent == false)
        {
            delete *it;
        }
	}

    m_anchors.clear();

	m_anchors.insert(m_anchors.begin(), anchor1);
	m_anchors.insert(m_anchors.end(), anchor2);

	btManifoldArray	m_manifoldArray;
	btVector3 m_touchingNormal;

	//std::cout << m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs() << std::endl;

	// Only caches the pairs, they don't have a lot of useful information
	btBroadphasePairArray& pairArray = m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray();
	int numPairs = pairArray.size();

	for (int i=0;i<numPairs;i++)
	{
		m_manifoldArray.clear();

		const btBroadphasePair& pair = pairArray[i];

		// The real broadphase's pair cache has the useful info
		btBroadphasePair* collisionPair = m_overlappingPairCache->getOverlappingPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);

		btCollisionObject* obj0 = static_cast<btCollisionObject*>(collisionPair->m_pProxy0->m_clientObject);
                btCollisionObject* obj1 = static_cast<btCollisionObject*>(collisionPair->m_pProxy1->m_clientObject);

		if (collisionPair->m_algorithm)
			collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray);

		//std::cout  << m_manifoldArray.size() << std::endl;

		for (int j=0;j<m_manifoldArray.size();j++)
		{
			btPersistentManifold* manifold = m_manifoldArray[j];
			btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0);
			for (int p=0;p<manifold->getNumContacts();p++)
			{
				const btManifoldPoint&pt = manifold->getContactPoint(p);

				btScalar dist = pt.getDistance();

				// Ensures the force is pointed outwards - may need to double check
				if (dist < 0.0)
				{

					m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??

					btRigidBody* rb = NULL;
					btVector3 pos;

					if (directionSign < 0)
					{
						rb = btRigidBody::upcast(obj1);
						pos = pt.m_positionWorldOnB;
					}
					else
					{
						rb = btRigidBody::upcast(obj0);
						pos = pt.m_positionWorldOnA;
					}

					if(rb)
					{
						const muscleAnchor* newAnchor = new muscleAnchor(rb, pos, m_touchingNormal, false, true);
						m_anchors.push_back(newAnchor);

                       /*
						btScalar mass = rb->getInvMass() == 0 ? 0.0 : 1.0 / rb->getInvMass();
						btVector3 impulse = mass * dt * m_touchingNormal * getTension() / getActualLength() * -1.0* dist;
						rb->applyImpulse(impulse, pos);
                        */
					}

				}
			}
		}

	}

    std::sort (m_anchors.begin(), m_anchors.end(), m_ac);

    std::size_t n = m_anchors.size();
    for (int i = 0; i < n; i++)
    {
        std::cout << m_anchors[i]->getWorldPosition() << std::endl;
    }

}

// This works ok at the moment. Need an effective way of determining if the rope is under an object
void MuscleNP::updateCollisionObject()
{
    btVector3 maxes(anchor2->getWorldPosition());
    btVector3 mins(anchor1->getWorldPosition());

    std::size_t n = m_anchors.size();
    for (std::size_t i = 1; i < n; i++)
    {
        btVector3 worldPos = m_anchors[i]->getWorldPosition();
        for (std::size_t j = 0; j < 3; j++)
        {
            if (worldPos[j] > maxes[j])
            {
                maxes[j] = worldPos[j];
            }
            else if (worldPos[j] < mins[j])
            {
                mins[j] = worldPos[j];
            }
        }
    }

    btVector3 from = anchor1->getWorldPosition();
	btVector3 to = anchor2->getWorldPosition();

	btTransform transform = tgUtil::getTransform(from, to);

	//std::cout << (to - from).length()/2.0 << std::endl;

    btQuaternion rot = transform.getRotation();

    btVector3 newDimensions = (maxes - mins).rotate(rot.getAxis(), rot.getAngle()) / 2.0;

    for (std::size_t i = 0; i < 3; i++)
    {
        ///@todo make configurable
        if (std::abs(newDimensions[i]) < 0.01)
        {
            newDimensions[i] = 0.01;
        }
        else
        {
            newDimensions[i] = std::abs(newDimensions[i]);
        }
    }

	btBoxShape* shape = tgCast::cast<btCollisionShape,  btBoxShape>(*m_ghostObject->getCollisionShape());
	/* Note that 1) this is listed as "use with care" in Bullet's documentation and
	 * 2) we had to remove the object from DemoApplication's render function in order for it to render properly
	 * changing from a non-contact object will break that behavior.
	 */
	shape->setImplicitShapeDimensions(newDimensions);
	m_ghostObject->setCollisionShape(shape);

    m_ghostObject->setWorldTransform(transform);

    // Erwin recommends this after changing collision shape: http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=4611
    // Doesn't seem to make much of a difference for us
    //m_ghostObject->getOverlappingPairCache()->cleanProxyFromPairs(m_ghostObject->getBroadphaseHandle(), m_dispatcher);

}

MuscleNP::anchorCompare::anchorCompare(const muscleAnchor* m1, const muscleAnchor* m2) :
ma1(m1),
ma2(m2)
{

}

bool MuscleNP::anchorCompare::operator() (const muscleAnchor* lhs, const muscleAnchor* rhs)
{
   btVector3 pt1 = ma1->getWorldPosition();
   btVector3 ptN = ma2->getWorldPosition();

   btVector3 pt2 = lhs->getWorldPosition();
   btVector3 pt3 = rhs->getWorldPosition();

   btScalar lhDot = (ptN - pt1).dot(pt2);
   btScalar rhDot = (ptN - pt1).dot(pt3);

   return lhDot < rhDot;
}

<commit_msg>First cut point pruning algorithm<commit_after>/*
 * Copyright © 2012, United States Government, as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All rights reserved.
 *
 * The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is licensed
 * under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
*/

/**
 * @file MuscleNP.cpp
 * @brief Definition of a massless cable with contact dynamics
 * $Id$
 */

// This object
#include "MuscleNP.h"

// NTRT
#include "tgcreator/tgUtil.h"
#include "core/muscleAnchor.h"
#include "core/tgCast.h"
#include "core/tgBulletUtil.h"
#include "core/tgWorld.h"
// The Bullet Physics library
#include "btBulletDynamicsCommon.h"
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
#include "BulletCollision/BroadphaseCollision/btDispatcher.h"
#include "BulletDynamics/Dynamics/btDynamicsWorld.h"
#include "BulletDynamics/Dynamics/btActionInterface.h"
#include "LinearMath/btDefaultMotionState.h"
#include "LinearMath/btQuaternion.h"

// The C++ Standard Library
#include <iostream>
#include <algorithm>    // std::sort
#include <cmath>

MuscleNP::MuscleNP(btPairCachingGhostObject* ghostObject,
 tgWorld& world,
 btRigidBody * body1,
 btVector3 pos1,
 btRigidBody * body2,
 btVector3 pos2,
 double coefK,
 double dampingCoefficient) :
Muscle2P (body1, pos1, body2, pos2, coefK, dampingCoefficient),
m_ghostObject(ghostObject),
m_overlappingPairCache(tgBulletUtil::worldToDynamicsWorld(world).getBroadphase()),
m_dispatcher(tgBulletUtil::worldToDynamicsWorld(world).getDispatcher()),
m_ac(anchor1, anchor2)
{

}

MuscleNP::~MuscleNP()
{

}

const btScalar MuscleNP::getActualLength() const
{
    btScalar length = 0;

    std::size_t n = m_anchors.size() - 1;
    for (std::size_t i = 0; i < n; i++)
    {
        length += (m_anchors[i]->getWorldPosition() - m_anchors[i+1]->getWorldPosition()).length();
    }

    return length;
}

btVector3 MuscleNP::calculateAndApplyForce(double dt)
{

	updateAnchorList(dt);

    // Apply forces

    updateCollisionObject();
}

void MuscleNP::updateAnchorList(double dt)
{
	std::vector<const muscleAnchor*>::iterator it = m_anchors.begin();
    muscleAnchor* temp;
	for (it = m_anchors.begin(); it != m_anchors.end(); it++)
	{
		if ((*it)->permanent == false)
        {
            delete *it;
        }
	}

    m_anchors.clear();

	btManifoldArray	m_manifoldArray;
	btVector3 m_touchingNormal;

	//std::cout << m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs() << std::endl;

	// Only caches the pairs, they don't have a lot of useful information
	btBroadphasePairArray& pairArray = m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray();
	int numPairs = pairArray.size();

	for (int i=0;i<numPairs;i++)
	{
		m_manifoldArray.clear();

		const btBroadphasePair& pair = pairArray[i];

		// The real broadphase's pair cache has the useful info
		btBroadphasePair* collisionPair = m_overlappingPairCache->getOverlappingPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);

		btCollisionObject* obj0 = static_cast<btCollisionObject*>(collisionPair->m_pProxy0->m_clientObject);
                btCollisionObject* obj1 = static_cast<btCollisionObject*>(collisionPair->m_pProxy1->m_clientObject);

		if (collisionPair->m_algorithm)
			collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray);

		//std::cout  << m_manifoldArray.size() << std::endl;

		for (int j=0;j<m_manifoldArray.size();j++)
		{
			btPersistentManifold* manifold = m_manifoldArray[j];
			btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0);
			for (int p=0;p<manifold->getNumContacts();p++)
			{
				const btManifoldPoint&pt = manifold->getContactPoint(p);

				btScalar dist = pt.getDistance();

				// Ensures the force is pointed outwards - may need to double check
				if (dist < 0.0)
				{

					m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??

					btRigidBody* rb = NULL;
					btVector3 pos;

					if (directionSign < 0)
					{
						rb = btRigidBody::upcast(obj1);
						pos = pt.m_positionWorldOnB;
					}
					else
					{
						rb = btRigidBody::upcast(obj0);
						pos = pt.m_positionWorldOnA;
					}

					if(rb)
					{
						const muscleAnchor* newAnchor = new muscleAnchor(rb, pos, m_touchingNormal, false, true);
						m_anchors.push_back(newAnchor);

                       /*
						btScalar mass = rb->getInvMass() == 0 ? 0.0 : 1.0 / rb->getInvMass();
						btVector3 impulse = mass * dt * m_touchingNormal * getTension() / getActualLength() * -1.0* dist;
						rb->applyImpulse(impulse, pos);
                        */
					}

				}
			}
		}

	}

    std::sort (m_anchors.begin(), m_anchors.end(), m_ac);

    // Add these last to ensure we're in the right order
    m_anchors.insert(m_anchors.begin(), anchor1);
	m_anchors.insert(m_anchors.end(), anchor2);

    // Find way to enter the loop without BS data
    int numPruned = 1;
    std::size_t i;
    while (numPruned > 0)
    {
        numPruned = 0;
        i = 1;
        while (i < m_anchors.size() - 1)
        {
            btVector3 back = m_anchors[i - 1]->getWorldPosition();
            btVector3 forward = m_anchors[i + 1]->getWorldPosition();

            btVector3 line = forward - back;

            // Maybe change to double if Bullet uses double?
            //std::cout << "Normals " <<  std::abs(line.dot( m_anchors[i]->contactNormal)) << std::endl;
            btScalar normalValue = std::abs(line.dot( m_anchors[i]->contactNormal));
            if (normalValue > 0.1)
            {
                std::cout << "Erased: " << normalValue << " ";
                delete m_anchors[i];
                m_anchors.erase(m_anchors.begin() + i);
                numPruned++;
            }
            /// @todo make configurable!
            #if (0)
            else if((m_anchors[i]->getWorldPosition() - m_anchors[i-1]->getWorldPosition()).length() < 0.01)
            {
                delete m_anchors[i];
                m_anchors.erase(m_anchors.begin() + i);
                numPruned++;
            }
            #endif
            else
            {
                i++;
            }
            std::cout << m_anchors.size() << " ";

        }

        std::cout << "Pruned: " << numPruned << std::endl;
    }

    std::size_t n = m_anchors.size();
    for (i = 0; i < n; i++)
    {
        std::cout << m_anchors[i]->getWorldPosition();

        if (i != 0 && i != n-1)
        {
            btVector3 back = m_anchors[i - 1]->getWorldPosition();
            btVector3 forward = m_anchors[i + 1]->getWorldPosition();

            btVector3 line = forward - back;

            std::cout << " " <<  line.dot( m_anchors[i]->contactNormal);
        }

        std::cout << std::endl;
    }

}

// This works ok at the moment. Need an effective way of determining if the rope is under an object
void MuscleNP::updateCollisionObject()
{
    btVector3 maxes(anchor2->getWorldPosition());
    btVector3 mins(anchor1->getWorldPosition());

    std::size_t n = m_anchors.size();
    for (std::size_t i = 1; i < n; i++)
    {
        btVector3 worldPos = m_anchors[i]->getWorldPosition();
        for (std::size_t j = 0; j < 3; j++)
        {
            if (worldPos[j] > maxes[j])
            {
                maxes[j] = worldPos[j];
            }
            else if (worldPos[j] < mins[j])
            {
                mins[j] = worldPos[j];
            }
        }
    }

    btVector3 from = anchor1->getWorldPosition();
	btVector3 to = anchor2->getWorldPosition();

	btTransform transform = tgUtil::getTransform(from, to);

	//std::cout << (to - from).length()/2.0 << std::endl;

    btQuaternion rot = transform.getRotation();

    btVector3 newDimensions = (maxes - mins).rotate(rot.getAxis(), rot.getAngle()) / 2.0;

    for (std::size_t i = 0; i < 3; i++)
    {
        ///@todo make configurable
        if (std::abs(newDimensions[i]) < 0.01)
        {
            newDimensions[i] = 0.01;
        }
        else
        {
            newDimensions[i] = std::abs(newDimensions[i]);
        }
    }

	btBoxShape* shape = tgCast::cast<btCollisionShape,  btBoxShape>(*m_ghostObject->getCollisionShape());
	/* Note that 1) this is listed as "use with care" in Bullet's documentation and
	 * 2) we had to remove the object from DemoApplication's render function in order for it to render properly
	 * changing from a non-contact object will break that behavior.
	 */
	shape->setImplicitShapeDimensions(newDimensions);
	m_ghostObject->setCollisionShape(shape);

    m_ghostObject->setWorldTransform(transform);

    // Erwin recommends this after changing collision shape: http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=4611
    // Doesn't seem to make much of a difference for us
    //m_ghostObject->getOverlappingPairCache()->cleanProxyFromPairs(m_ghostObject->getBroadphaseHandle(), m_dispatcher);

}

MuscleNP::anchorCompare::anchorCompare(const muscleAnchor* m1, const muscleAnchor* m2) :
ma1(m1),
ma2(m2)
{

}

bool MuscleNP::anchorCompare::operator() (const muscleAnchor* lhs, const muscleAnchor* rhs)
{
   btVector3 pt1 = ma1->getWorldPosition();
   btVector3 ptN = ma2->getWorldPosition();

   btVector3 pt2 = lhs->getWorldPosition();
   btVector3 pt3 = rhs->getWorldPosition();

   btScalar lhDot = (ptN - pt1).dot(pt2);
   btScalar rhDot = (ptN - pt1).dot(pt3);

   return lhDot < rhDot;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017, Arm Limited and affiliates.
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "UBLOX_PPP_CellularNetwork.h"

using namespace mbed;

UBLOX_PPP_CellularNetwork::UBLOX_PPP_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler)
{
}

UBLOX_PPP_CellularNetwork::~UBLOX_PPP_CellularNetwork()
{
}

bool UBLOX_PPP_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
    return requested_stack == IPV4_STACK ? true : false;
}

bool UBLOX_PPP_CellularNetwork::has_registration(RegistrationType reg_type)
{
    return (reg_type == C_REG || reg_type == C_GREG);
}

nsapi_error_t UBLOX_LISA_U_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opRat)
{
    _op_act = RAT_UNKNOWN;
    return NSAPI_ERROR_UNSUPPORTED;
}
<commit_msg>Cellular: Fixed rebase error.<commit_after>/*
 * Copyright (c) 2017, Arm Limited and affiliates.
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "UBLOX_PPP_CellularNetwork.h"

using namespace mbed;

UBLOX_PPP_CellularNetwork::UBLOX_PPP_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler)
{
}

UBLOX_PPP_CellularNetwork::~UBLOX_PPP_CellularNetwork()
{
}

bool UBLOX_PPP_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
    return requested_stack == IPV4_STACK ? true : false;
}

bool UBLOX_PPP_CellularNetwork::has_registration(RegistrationType reg_type)
{
    return (reg_type == C_REG || reg_type == C_GREG);
}

nsapi_error_t UBLOX_PPP_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opRat)
{
    _op_act = RAT_UNKNOWN;
    return NSAPI_ERROR_UNSUPPORTED;
}
<|endoftext|>


<commit_before><commit_msg>#88614# page has a backgroundobject only if it realy has one<commit_after><|endoftext|>


<commit_before>/*****************************************************************************
 * menus.hpp : Menus handling
 ****************************************************************************
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifndef QVLC_MENUS_H_
#define QVLC_MENUS_H_

#include "qt4.hpp"

#include <QObject>
#include <QAction>
#include <vector>

/* Folder vs. Directory */
#if defined( WIN32 ) || defined(__APPLE__)
#define I_OPEN_FOLDER N_("Open &Folder...")
#else
#define I_OPEN_FOLDER N_("Open D&irectory...")
#endif //WIN32

using namespace std;

class QMenu;
class QMenuBar;
class QSystemTrayIcon;

class MenuItemData : public QObject
{
    Q_OBJECT

public:
    MenuItemData( QObject* parent, vlc_object_t *_p_obj, int _i_type,
                  vlc_value_t _val, const char *_var ) : QObject( parent )
    {
        p_obj = _p_obj;
        i_val_type = _i_type;
        val = _val;
        psz_var = strdup( _var );
    }
    virtual ~MenuItemData()
    {
        free( psz_var );
        if( ( i_val_type & VLC_VAR_TYPE) == VLC_VAR_STRING )
            free( val.psz_string );
    }

    vlc_object_t *p_obj;
    vlc_value_t val;
    char *psz_var;

private:
    int i_val_type;
};

class QVLCMenu : public QObject
{
    Q_OBJECT;
    friend class MenuFunc;

public:
    /* Main bar creation */
    static void createMenuBar( MainInterface *mi, intf_thread_t * );

    /* Popups Menus */
    static void PopupMenu( intf_thread_t *, bool );
    static void AudioPopupMenu( intf_thread_t * );
    static void VideoPopupMenu( intf_thread_t * );
    static void MiscPopupMenu( intf_thread_t * );

    /* Systray */
    static void updateSystrayMenu( MainInterface *,intf_thread_t  *,
                                   bool b_force_visible = false);

    /* Actions */
    static void DoAction( QObject * );

private:
    /* All main Menus */
    static QMenu *FileMenu( intf_thread_t *, QWidget * );
    static QMenu *SDMenu( intf_thread_t *, QWidget * );

    static QMenu *ToolsMenu( QMenu * );
    static QMenu *ToolsMenu( QWidget * );

    static QMenu *ViewMenu( intf_thread_t *, MainInterface *,
                            bool with = true );
    static QMenu *InterfacesMenu( intf_thread_t *p_intf, QMenu * );

    static QMenu *NavigMenu( intf_thread_t *, QMenu * );
    static QMenu *NavigMenu( intf_thread_t *, QWidget * );
    static QMenu *RebuildNavigMenu( intf_thread_t *, QMenu *);

    static QMenu *VideoMenu( intf_thread_t *, QMenu * );
    static QMenu *VideoMenu( intf_thread_t *, QWidget * );

    static QMenu *AudioMenu( intf_thread_t *, QMenu * );
    static QMenu *AudioMenu( intf_thread_t *, QWidget * );

    static QMenu *HelpMenu( QWidget * );

    /* Popups Menus */
    static void PopupMenuStaticEntries( QMenu *menu );
    static void PopupPlayEntries( QMenu *menu, intf_thread_t *p_intf,
                                         input_thread_t *p_input );
    static void PopupMenuControlEntries( QMenu *menu, intf_thread_t *p_intf );
    static void PopupMenuPlaylistControlEntries( QMenu *menu, intf_thread_t *p_intf );

    /* Generic automenu methods */
    static QMenu * Populate( intf_thread_t *, QMenu *current,
                             vector<const char*>&, vector<vlc_object_t *>& );

    static void CreateAndConnect( QMenu *, const char *, QString, QString,
                                  int, vlc_object_t *, vlc_value_t, int,
                                  bool c = false );
    static void UpdateItem( intf_thread_t *, QMenu *, const char *,
                            vlc_object_t *, bool );
    static int CreateChoicesMenu( QMenu *,const char *, vlc_object_t *, bool );

    /* recentMRL menu */
    static QMenu *recentsMenu;

public slots:
    static void updateRecents( intf_thread_t * );
};

class MenuFunc : public QObject
{
    Q_OBJECT

public:
    MenuFunc( QMenu *_menu, int _id ) : QObject( (QObject *)_menu ),
                                        menu( _menu ), id( _id ){}

    void doFunc( intf_thread_t *p_intf)
    {
        switch( id )
        {
            case 1: QVLCMenu::AudioMenu( p_intf, menu ); break;
            case 2: QVLCMenu::VideoMenu( p_intf, menu ); break;
            case 3: QVLCMenu::RebuildNavigMenu( p_intf, menu ); break;
            case 4: QVLCMenu::InterfacesMenu( p_intf, menu ); break;
        }
    }
private:
    int id;
    QMenu *menu;
};

#endif
<commit_msg>Qt4: hold objet while the popup menu is active<commit_after>/*****************************************************************************
 * menus.hpp : Menus handling
 ****************************************************************************
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifndef QVLC_MENUS_H_
#define QVLC_MENUS_H_

#include "qt4.hpp"

#include <QObject>
#include <QAction>
#include <vector>

/* Folder vs. Directory */
#if defined( WIN32 ) || defined(__APPLE__)
#define I_OPEN_FOLDER N_("Open &Folder...")
#else
#define I_OPEN_FOLDER N_("Open D&irectory...")
#endif //WIN32

using namespace std;

class QMenu;
class QMenuBar;
class QSystemTrayIcon;

class MenuItemData : public QObject
{
    Q_OBJECT

public:
    MenuItemData( QObject* parent, vlc_object_t *_p_obj, int _i_type,
                  vlc_value_t _val, const char *_var ) : QObject( parent )
    {
        p_obj = _p_obj;
        if( p_obj )
            vlc_object_hold( p_obj );
        i_val_type = _i_type;
        val = _val;
        psz_var = strdup( _var );
    }
    virtual ~MenuItemData()
    {
        free( psz_var );
        if( ( i_val_type & VLC_VAR_TYPE) == VLC_VAR_STRING )
            free( val.psz_string );
        if( p_obj )
            vlc_object_release( p_obj );
    }

    vlc_object_t *p_obj;
    vlc_value_t val;
    char *psz_var;

private:
    int i_val_type;
};

class QVLCMenu : public QObject
{
    Q_OBJECT;
    friend class MenuFunc;

public:
    /* Main bar creation */
    static void createMenuBar( MainInterface *mi, intf_thread_t * );

    /* Popups Menus */
    static void PopupMenu( intf_thread_t *, bool );
    static void AudioPopupMenu( intf_thread_t * );
    static void VideoPopupMenu( intf_thread_t * );
    static void MiscPopupMenu( intf_thread_t * );

    /* Systray */
    static void updateSystrayMenu( MainInterface *,intf_thread_t  *,
                                   bool b_force_visible = false);

    /* Actions */
    static void DoAction( QObject * );

private:
    /* All main Menus */
    static QMenu *FileMenu( intf_thread_t *, QWidget * );
    static QMenu *SDMenu( intf_thread_t *, QWidget * );

    static QMenu *ToolsMenu( QMenu * );
    static QMenu *ToolsMenu( QWidget * );

    static QMenu *ViewMenu( intf_thread_t *, MainInterface *,
                            bool with = true );
    static QMenu *InterfacesMenu( intf_thread_t *p_intf, QMenu * );

    static QMenu *NavigMenu( intf_thread_t *, QMenu * );
    static QMenu *NavigMenu( intf_thread_t *, QWidget * );
    static QMenu *RebuildNavigMenu( intf_thread_t *, QMenu *);

    static QMenu *VideoMenu( intf_thread_t *, QMenu * );
    static QMenu *VideoMenu( intf_thread_t *, QWidget * );

    static QMenu *AudioMenu( intf_thread_t *, QMenu * );
    static QMenu *AudioMenu( intf_thread_t *, QWidget * );

    static QMenu *HelpMenu( QWidget * );

    /* Popups Menus */
    static void PopupMenuStaticEntries( QMenu *menu );
    static void PopupPlayEntries( QMenu *menu, intf_thread_t *p_intf,
                                         input_thread_t *p_input );
    static void PopupMenuControlEntries( QMenu *menu, intf_thread_t *p_intf );
    static void PopupMenuPlaylistControlEntries( QMenu *menu, intf_thread_t *p_intf );

    /* Generic automenu methods */
    static QMenu * Populate( intf_thread_t *, QMenu *current,
                             vector<const char*>&, vector<vlc_object_t *>& );

    static void CreateAndConnect( QMenu *, const char *, QString, QString,
                                  int, vlc_object_t *, vlc_value_t, int,
                                  bool c = false );
    static void UpdateItem( intf_thread_t *, QMenu *, const char *,
                            vlc_object_t *, bool );
    static int CreateChoicesMenu( QMenu *,const char *, vlc_object_t *, bool );

    /* recentMRL menu */
    static QMenu *recentsMenu;

public slots:
    static void updateRecents( intf_thread_t * );
};

class MenuFunc : public QObject
{
    Q_OBJECT

public:
    MenuFunc( QMenu *_menu, int _id ) : QObject( (QObject *)_menu ),
                                        menu( _menu ), id( _id ){}

    void doFunc( intf_thread_t *p_intf)
    {
        switch( id )
        {
            case 1: QVLCMenu::AudioMenu( p_intf, menu ); break;
            case 2: QVLCMenu::VideoMenu( p_intf, menu ); break;
            case 3: QVLCMenu::RebuildNavigMenu( p_intf, menu ); break;
            case 4: QVLCMenu::InterfacesMenu( p_intf, menu ); break;
        }
    }
private:
    int id;
    QMenu *menu;
};

#endif
<|endoftext|>