<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "parser/EDDIGrammar.hpp"

using namespace eddic;

EddiGrammar::EddiGrammar(const Lexer& lexer) :
        EddiGrammar::base_type(program, "EDDI Grammar"),
        value(lexer),
        condition(lexer),
        type(lexer){

    else_if_ %=
            lexer.else_
        >>  lexer.if_
        >>  lexer.left_parenth
        >>  condition
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    else_ %=
            lexer.else_
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    if_ %=
            lexer.if_
        >>  lexer.left_parenth
        >>  condition
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace
        >>  *(else_if_)
        >>  -(else_);

    for_ %=
            lexer.for_
        >   lexer.left_parenth
        >   -declaration
        >   lexer.stop
        >   -condition
        >   lexer.stop
        >   -repeatable_instruction
        >   lexer.right_parenth
        >   lexer.left_brace
        >   (*instruction)
        >   lexer.right_brace;

    foreach_ =
            lexer.foreach_
        >>  lexer.left_parenth
        >>  lexer.word
        >>  lexer.word
        >>  lexer.from_
        >>  lexer.integer
        >>  lexer.to_
        >>  lexer.integer
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    foreachin_ =
            lexer.foreach_
        >>  lexer.left_parenth
        >>  lexer.word
        >>  lexer.word
        >>  lexer.in_
        >>  lexer.word
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    while_ %=
            lexer.while_
        >   lexer.left_parenth
        >   condition
        >   lexer.right_parenth
        >   lexer.left_brace
        >   *(instruction)
        >   lexer.right_brace;

    declaration %=
            lexer.word
        >>  lexer.word
        >>  -(lexer.assign >> value);

    arrayDeclaration %=
            lexer.word
        >>  lexer.word
        >>  lexer.left_bracket
        >>  lexer.integer
        >>  lexer.right_bracket;

    assignment %=
            lexer.word
        >>  lexer.assign
        >>  value;

    return_ %=
            lexer.return_
        >>  value;

    arrayAssignment %=
            lexer.word
        >>  lexer.left_bracket
        >>  value
        >>  lexer.right_bracket
        >>  lexer.assign
        >>  value;

    globalDeclaration %=
            lexer.word
        >>  lexer.word
        >>  -(lexer.assign >> value.constant)
        >>  lexer.stop;

    globalArrayDeclaration %=
            lexer.word
        >>  lexer.word
        >>  lexer.left_bracket
        >>  lexer.integer
        >>  lexer.right_bracket
        >>  lexer.stop;

    functionCall %=
            lexer.word
        >>  lexer.left_parenth
        >>  -( value >> *( lexer.comma > value))
        >>  lexer.right_parenth;

    swap %=
            lexer.word
        >>  lexer.swap
        >>  lexer.word;

    instruction %=
            (functionCall > lexer.stop)
        |   (assignment > lexer.stop)
        |   (declaration >> lexer.stop)
        |   (arrayDeclaration >> lexer.stop)
        |   (arrayAssignment > lexer.stop)
        |   (return_ > lexer.stop)
        |   if_
        |   for_
        |   while_
        |   foreach_
        |   foreachin_
        |   (swap > lexer.stop);

    repeatable_instruction = assignment | declaration | swap;

    arg %=
            type
        >>  lexer.word;

    function %=
            lexer.word
        >>  lexer.word
        >>  lexer.left_parenth
        >>  -( arg >> *( lexer.comma > arg))
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    program %=
            qi::eps
        >>  *(function | globalDeclaration | globalArrayDeclaration);

    //Name the rules
    globalDeclaration.name("EDDI global variable");
    function.name("EDDI function declaration");
    program.name("EDDI program");
}
<commit_msg>Fix the grammar for return values<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "parser/EDDIGrammar.hpp"

using namespace eddic;

EddiGrammar::EddiGrammar(const Lexer& lexer) :
        EddiGrammar::base_type(program, "EDDI Grammar"),
        value(lexer),
        condition(lexer),
        type(lexer){

    else_if_ %=
            lexer.else_
        >>  lexer.if_
        >>  lexer.left_parenth
        >>  condition
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    else_ %=
            lexer.else_
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    if_ %=
            lexer.if_
        >>  lexer.left_parenth
        >>  condition
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace
        >>  *(else_if_)
        >>  -(else_);

    for_ %=
            lexer.for_
        >   lexer.left_parenth
        >   -declaration
        >   lexer.stop
        >   -condition
        >   lexer.stop
        >   -repeatable_instruction
        >   lexer.right_parenth
        >   lexer.left_brace
        >   (*instruction)
        >   lexer.right_brace;

    foreach_ =
            lexer.foreach_
        >>  lexer.left_parenth
        >>  lexer.word
        >>  lexer.word
        >>  lexer.from_
        >>  lexer.integer
        >>  lexer.to_
        >>  lexer.integer
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    foreachin_ =
            lexer.foreach_
        >>  lexer.left_parenth
        >>  lexer.word
        >>  lexer.word
        >>  lexer.in_
        >>  lexer.word
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    while_ %=
            lexer.while_
        >   lexer.left_parenth
        >   condition
        >   lexer.right_parenth
        >   lexer.left_brace
        >   *(instruction)
        >   lexer.right_brace;

    declaration %=
            lexer.word
        >>  lexer.word
        >>  -(lexer.assign >> value);

    arrayDeclaration %=
            lexer.word
        >>  lexer.word
        >>  lexer.left_bracket
        >>  lexer.integer
        >>  lexer.right_bracket;

    assignment %=
            lexer.word
        >>  lexer.assign
        >>  value;

    return_ %=
            lexer.return_
        >>  value
        >>  lexer.stop;

    arrayAssignment %=
            lexer.word
        >>  lexer.left_bracket
        >>  value
        >>  lexer.right_bracket
        >>  lexer.assign
        >>  value;

    globalDeclaration %=
            lexer.word
        >>  lexer.word
        >>  -(lexer.assign >> value.constant)
        >>  lexer.stop;

    globalArrayDeclaration %=
            lexer.word
        >>  lexer.word
        >>  lexer.left_bracket
        >>  lexer.integer
        >>  lexer.right_bracket
        >>  lexer.stop;

    functionCall %=
            lexer.word
        >>  lexer.left_parenth
        >>  -( value >> *( lexer.comma > value))
        >>  lexer.right_parenth;

    swap %=
            lexer.word
        >>  lexer.swap
        >>  lexer.word;

    instruction %=
            (functionCall > lexer.stop)
        |   (assignment > lexer.stop)
        |   (declaration >> lexer.stop)
        |   (arrayDeclaration >> lexer.stop)
        |   (arrayAssignment > lexer.stop)
        |   if_
        |   for_
        |   while_
        |   foreach_
        |   foreachin_
        |   return_
        |   (swap > lexer.stop);

    repeatable_instruction = assignment | declaration | swap;

    arg %=
            type
        >>  lexer.word;

    function %=
            lexer.word
        >>  lexer.word
        >>  lexer.left_parenth
        >>  -( arg >> *( lexer.comma > arg))
        >>  lexer.right_parenth
        >>  lexer.left_brace
        >>  *(instruction)
        >>  lexer.right_brace;

    program %=
            qi::eps
        >>  *(function | globalDeclaration | globalArrayDeclaration);

    //Name the rules
    globalDeclaration.name("EDDI global variable");
    function.name("EDDI function declaration");
    program.name("EDDI program");
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Copyright (c) 2017 The UltimateOnlineCash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "primitives/block.h"

#include "hash.h"
#include "tinyformat.h"
#include "utilstrencodings.h"
#include "crypto/common.h"
#include "crypto/neoscrypt.h"

uint256 CBlockHeader::GetHash() const
{
    return SerializeHash(*this);
}

uint256 CBlockHeader::GetPoWHash() const
{
    unsigned int profile = 0x0;
    uint256 hash;
    neoscrypt((unsigned char *) &nVersion, (unsigned char *) &hash, profile);
	return(hash);
}

std::string CBlock::ToString() const
{
    std::stringstream s;
    s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
        GetHash().ToString(),
        nVersion,
        hashPrevBlock.ToString(),
        hashMerkleRoot.ToString(),
        nTime, nBits, nNonce,
        vtx.size());
    for (const auto& tx : vtx) {
        s << "  " << tx->ToString() << "\n";
    }
    return s.str();
}<commit_msg>Update Neoscrypt<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Copyright (c) 2017 The UltimateOnlineCash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "primitives/block.h"

#include "hash.h"
#include "tinyformat.h"
#include "utilstrencodings.h"
#include "crypto/common.h"
#include "crypto/neoscrypt.h"

uint256 CBlockHeader::GetHash() const
{
    return SerializeHash(*this);
}

uint256 CBlockHeader::GetPoWHash() const
{
    unsigned int profile = 0x0;
    uint256 thash;
    neoscrypt((unsigned char *) &nVersion, (unsigned char *) &thash, profile);
    return thash;
}

std::string CBlock::ToString() const
{
    std::stringstream s;
    s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
        GetHash().ToString(),
        nVersion,
        hashPrevBlock.ToString(),
        hashMerkleRoot.ToString(),
        nTime, nBits, nNonce,
        vtx.size());
    for (const auto& tx : vtx) {
        s << "  " << tx->ToString() << "\n";
    }
    return s.str();
}
<|endoftext|>


<commit_before>#include <errno.h>
#include <assert.h>

#include "Endian.hh"
#include "TreeGram.hh"
#include "tools.hh"

static std::string format_str("cis-binlm2\n");

TreeGram::TreeGram()
  : m_type(BACKOFF),
    m_order(0),
    m_last_order(0)
{
}

void
TreeGram::reserve_nodes(int nodes)
{
  m_nodes.clear();
  m_nodes.reserve(nodes);
  m_nodes.push_back(Node(0, -99, 0, -1));
}

void
TreeGram::set_interpolation(const std::vector<float> &interpolation)
{
  m_interpolation = interpolation;
}

void
TreeGram::print_gram(FILE *file, const Gram &gram)
{
  for (int i = 0; i < gram.size(); i++) {
    fprintf(file, "%d ", gram[i]);
  }
  fputc('\n', file);
}

void
TreeGram::check_order(const Gram &gram)
{
  // Order must be the same or the next.
  if (gram.size() < m_last_gram.size() ||
      gram.size() > m_last_gram.size() + 1)
  {
    fprintf(stderr, "TreeGram::check_order(): "
	    "trying to insert %d-gram after %d-gram\n",
	    gram.size(), m_last_gram.size());
    print_gram(stderr, gram);
    exit(1);
  }

  // Unigrams must be in the correct places
  if (gram.size() == 1) {
    if (gram[0] != m_nodes.size()) {
      fprintf(stderr, "TreeGram::check_order(): "
	      "trying to insert 1-gram %d to node %d\n",
	      gram[0], m_nodes.size());
      exit(1);
    }
  }

  // With the same order, the grams must inserted in sorted order.
  if (gram.size() == m_last_gram.size()) {
    int i;
    for (i = 0; i < gram.size(); i++) {

      // Skipping grams
      if (gram[i] > m_last_gram[i])
	break;

      // Not in order
      if (gram[i] < m_last_gram[i]) {
	fprintf(stderr, "TreeGram::check_order(): "
		"gram not in sorted order\n");
	print_gram(stderr, gram);
	exit(1);
      }
    }

    // Duplicate?
    if (i == gram.size()) {
      fprintf(stderr, "TreeGram::check_order(): "
	      "duplicate gram\n");
      print_gram(stderr, gram);
      exit(1);
    }
  }
}

// Note that 'last' is not included in the range.
int
TreeGram::binary_search(int word, int first, int last)
{
  int middle;
  int half;

  int len = last - first;

  while (len > 5) { // FIXME: magic threshold to do linear search
    half = len / 2;
    middle = first + half;

    // Equal
    if (m_nodes[middle].word == word)
      return middle;

    // First half
    if (m_nodes[middle].word > word) {
      last = middle;
      len = last - first;
    }

    // Second half
    else {
      first = middle + 1;
      len = last - first;
    }
  }

  while (first < last) {
    if (m_nodes[first].word == word)
      return first;
    first++;
  }

  return -1;
}

// Returns unigram if node_index < 0
int
TreeGram::find_child(int word, int node_index)
{
  if (word < 0 || word >= m_words.size()) {
    fprintf(stderr, "TreeGram::find_child(): "
	    "index %d out of vocabulary size %d\n", word, m_words.size());
    exit(1);
  }

  if (node_index < 0)
    return word;

  assert(node_index < m_nodes.size() - 1);

  int first = m_nodes[node_index].child_index;
  int last = m_nodes[node_index + 1].child_index; // not included
  if (first < 0 || last < 0)
    return -1;

  return binary_search(word, first, last);
}

/// Finds the path to the current gram.
//
// PRECONDITIONS:
// - m_insert_stack contains the indices of 'm_last_gram'
//
// POSTCONDITIONS:
// - m_insert_stack contains the indices of 'gram' without the last word
void
TreeGram::find_path(const Gram &gram)
{
  int prev = -1;
  int order = 0;
  int index;

  assert(gram.size() > 1);

  // The beginning of the path can be found quickly by using the index
  // stack.
  while (1) {
    assert(order < m_last_gram.size() - 1);
    if (gram[order] != m_last_gram[order])
      break;
    order++;
  }
  m_insert_stack.resize(order);

  // The rest of the path must be searched.
  order--;
  if (order < 0)
    prev = -1;
  else
    prev = m_insert_stack[order];

  while (order < m_last_gram.size() - 1) {
    index = find_child(gram[order], prev);
    if (index < 0) {
      fprintf(stderr, "prefix not found\n");
      print_gram(stderr, gram);
      exit(1);
    }

    m_insert_stack.push_back(index);

    prev = index;
    order++;
  }
}

void
TreeGram::add_gram(const Gram &gram, float log_prob, float back_off)
{
  if (m_nodes.empty()) {
    fprintf(stderr, "TreeGram::add_gram(): "
	    "nodes must be reserved before calling this function\n");
    exit(1);
  }

  check_order(gram);

  // Update order counts
  if (gram.size() == m_last_gram.size() + 1) {
    m_order_count.push_back(0);
    m_order++;
  }
  assert(m_order_count.size() == gram.size());
  m_order_count[gram.size()]++;

  // Handle unigrams separately
  if (gram.size() == 1) {

    // OOV can be updated anytime.
    if (gram[0] == 0) {
      m_nodes[0].log_prob = log_prob;
      m_nodes[0].back_off = back_off;
    }

    // Unigram which is not OOV
    else
      m_nodes.push_back(Node(gram[0], log_prob, back_off, -1));
  }

  // 2-grams or higher
  else {
    // Update the path
    find_path(gram);

    if (m_nodes[m_insert_stack.back()].child_index < 0)
      m_nodes[m_insert_stack.back()].child_index = m_nodes.size();

    m_nodes.push_back(Node(gram.back(), log_prob, back_off, -1));
    m_nodes[m_insert_stack.back() + 1].child_index = m_nodes.size();
  }

  m_last_gram = gram;
  assert(m_order == m_last_gram.size());
}

void
TreeGram::write(FILE *file, bool reflip)
{
  fputs(format_str.c_str(), file);

  // Write type and interpolation weights
  if (m_type == BACKOFF)
    fputs("backoff\n", file);
  else if (m_type == INTERPOLATED)
    fputs("interpolated\n", file);

  fprintf(file, "%d\n", num_words());
  for (int i = 0; i < num_words(); i++)
    fprintf(file, "%s\n", word(i).c_str());
  fprintf(file, "%d %d\n", m_order, m_nodes.size());

  // Use correct endianity
  if (Endian::big)
    flip_endian();

  // Write possible interpolation weights
  if (m_type == INTERPOLATED) {
    assert(m_interpolation.size() == m_order);
    fwrite(&m_interpolation[0], m_order * sizeof(m_interpolation[0]), 1, file);
  }

  // Write nodes
  fwrite(&m_nodes[0], m_nodes.size() * sizeof(TreeGram::Node), 1, file);

  if (ferror(file)) {
    fprintf(stderr, "TreeGram::write(): write error: %s\n", strerror(errno));
    exit(1);
  }

  // Restore to original endianess
  if (Endian::big && reflip)
    flip_endian();
}

void
TreeGram::read(FILE *file)
{
  std::string line;
  int words;
  bool ret;

  // Read the header
  ret = read_string(&line, format_str.length(), file);
  if (!ret || line != format_str) {
    fprintf(stderr, "TreeGram::read(): invalid file format\n");
    exit(1);
  }

  // Read LM type
  read_line(&line, file);
  chomp(&line);
  if (line == "backoff")
    m_type = BACKOFF;
  else if (line == "interpolated")
    m_type = INTERPOLATED;
  else {
    fprintf(stderr, "TreeGram::read(): invalid type: %s\n", line.c_str());
    exit(1);
  }

  // Read the number of words
  if (!read_line(&line, file)) {
    fprintf(stderr, "TreeGram::read(): unexpected end of file\n");
    exit(1);
  }
  words = atoi(line.c_str());
  if (words < 1) {
    fprintf(stderr, "TreeGram::read(): invalid number of words: %s\n",
	    line.c_str());
    exit(1);
  }

  // Read the vocabulary
  for (int i=0; i < words; i++) {
    if (!read_line(&line, file)) {
      fprintf(stderr, "TreeGram::read(): "
	      "read error while reading vocabulary\n");
      exit(1);
    }
    chomp(&line);
    add_word(line);
  }

  // Read the order and the number of nodes
  int m_nodes_size;
  fscanf(file, "%d %d\n", &m_order, &m_nodes_size);
  reserve_nodes(m_nodes_size);

  // Read the possible interpolation weights
  if (m_type == INTERPOLATED) {
    m_interpolation.resize(m_order);
    fread(&m_interpolation[0], sizeof(float) * m_order, 1, file);
  }

  // Read the nodes
  size_t block_size = m_nodes.size() * sizeof(TreeGram::Node);
  size_t blocks_read = fread(&m_nodes[0], block_size, 1, file);
  if (blocks_read != 1) {
      fprintf(stderr, "TreeGram::read(): "
	      "read error while reading ngrams\n");
      exit(1);
  }

  if (Endian::big)
    flip_endian();
}

void
TreeGram::flip_endian()
{
  assert(sizeof(m_nodes[0].word == 4));
  assert(sizeof(m_nodes[0].log_prob == 4));
  assert(sizeof(m_nodes[0].back_off == 4));
  assert(sizeof(m_nodes[0].child_index == 4));

  if (m_type == INTERPOLATED) {
    assert(m_interpolation.size() == m_order);
    Endian::convert(&m_interpolation[0], 4 * m_order);
  }

  for (int i = 0; i < m_nodes.size(); i++) {
    Endian::convert(&m_nodes[i].word, 4);
    Endian::convert(&m_nodes[i].log_prob, 4);
    Endian::convert(&m_nodes[i].back_off, 4);
    Endian::convert(&m_nodes[i].child_index, 4);
  }
}

// Fetch the node indices of the requested gram to m_fetch_stack as
// far as found in the tree structure.
void
TreeGram::fetch_gram(const Gram &gram, int first)
{
  int prev = -1;
  m_fetch_stack.clear();

  while (m_fetch_stack.size() < gram.size()) {
    int node = find_child(gram[first], prev);
    if (node < 0)
      break;
    m_fetch_stack.push_back(node);
    first++;
    node = prev;
  }
}

float
TreeGram::log_prob(const Gram &gram)
{
  assert(gram.size() > 0);

  float log_prob = 0;

  // Denote by (w(1) w(2) ... w(N)) the ngram that was requested.  The
  // log-probability of the back-off model is computed as follows:

  // Iterate n = 1..N:
  // - If (w(n) ... w(N)) not found, add the possible (w(n) ... w(N-1) backoff
  // - Otherwise, add the log-prob and return.
  int n = 0;
  while (1) {
    assert(n < gram.size());
    fetch_gram(gram, n);
    assert(m_fetch_stack.size() > 0);

    // Full gram found?
    if (m_fetch_stack.size() == gram.size()) {
      log_prob += m_nodes[m_fetch_stack.back()].log_prob;
      m_last_order = gram.size() - n;
      break;
    }

    // Back-off found?
    if (m_fetch_stack.size() == gram.size() - 1)
      log_prob += m_nodes[m_fetch_stack.back()].back_off;

    n++;
  }

  return log_prob;
}

TreeGram::Iterator::Iterator(TreeGram *gram)
  : m_gram(gram)
{
  if (gram)
    reset(gram);
}

void
TreeGram::Iterator::reset(TreeGram *gram)
{
  assert(gram);
  m_gram = gram;
  m_index_stack.clear();
  m_index_stack.resize(gram->m_order);
}

bool
TreeGram::Iterator::next()
{
  bool backtrack = false;

  // Start the search
  if (m_index_stack.empty()) {
    m_index_stack.push_back(0);
    return true;
  }

  // Go to the next node.  Backtrack if necessary.
  while (1) {
    assert(!m_index_stack.empty());
    int index = m_index_stack.back();
    TreeGram::Node *node = &m_gram->m_nodes[index];

    // End of the structure?
    if (index == m_gram->m_nodes.size() - 1)
      return false;

    // If not backtracking, try diving deeper
    if (!backtrack) {
      // Do we have children?
      if (node->child_index > 0 && (node+1)->child_index > 0) {
	m_index_stack.push_back(node->child_index);
	return true;
      }
    }
    backtrack = false;

    // No children, try siblings
    if (m_index_stack.size() == 1) {
      // Unigram level: we have always siblings
      index++;
      assert(index < m_gram->m_order_count[0]);
      return true;
    }
    else {
      // Higher order
      m_index_stack.pop_back();
      TreeGram::Node *parent = &m_gram->m_nodes[m_index_stack.back()];

      // Do we have more siblings?
      index++;
      if (index < (parent+1)->child_index) {
	m_index_stack.push_back(index);
	return true;
      }

      // No more siblings, backtrack.
      backtrack = true;
    }
  }
}

bool
TreeGram::Iterator::next_order(int order)
{
  if (order < 1 || order > m_gram->m_order) {
    fprintf(stderr, "TreeGram::Iterator::next_order(): invalid order %d\n",
	    order);
    exit(1);
  }

  while (1) {
    if (!next())
      return false;

    if (m_index_stack.size() == order)
      return true;
  }
}

const TreeGram::Node&
TreeGram::Iterator::node()
{
  assert(m_gram);
  assert(!m_index_stack.empty());

  return m_gram->m_nodes[m_index_stack.back()];
}
<commit_msg>*** empty log message ***<commit_after>#include <errno.h>
#include <assert.h>

#include "Endian.hh"
#include "TreeGram.hh"
#include "tools.hh"

static std::string format_str("cis-binlm2\n");

TreeGram::TreeGram()
  : m_type(BACKOFF),
    m_order(0),
    m_last_order(0)
{
}

void
TreeGram::reserve_nodes(int nodes)
{
  m_nodes.clear();
  m_nodes.reserve(nodes);
  m_nodes.push_back(Node(0, -99, 0, -1));
}

void
TreeGram::set_interpolation(const std::vector<float> &interpolation)
{
  m_interpolation = interpolation;
}

void
TreeGram::print_gram(FILE *file, const Gram &gram)
{
  for (int i = 0; i < gram.size(); i++) {
    fprintf(file, "%d ", gram[i]);
  }
  fputc('\n', file);
}

void
TreeGram::check_order(const Gram &gram)
{
  // UNK can be updated anytime
  if (gram.size() == 1 && gram[0] == 0)
    return;

  // Order must be the same or the next.
  if (gram.size() < m_last_gram.size() ||
      gram.size() > m_last_gram.size() + 1)
  {
    fprintf(stderr, "TreeGram::check_order(): "
	    "trying to insert %d-gram after %d-gram\n",
	    gram.size(), m_last_gram.size());
    print_gram(stderr, gram);
    exit(1);
  }

  // Unigrams must be in the correct places
  if (gram.size() == 1) {
    if (gram[0] != m_nodes.size()) {
      fprintf(stderr, "TreeGram::check_order(): "
	      "trying to insert 1-gram %d to node %d\n",
	      gram[0], m_nodes.size());
      exit(1);
    }
  }

  // With the same order, the grams must inserted in sorted order.
  if (gram.size() == m_last_gram.size()) {
    int i;
    for (i = 0; i < gram.size(); i++) {

      // Skipping grams
      if (gram[i] > m_last_gram[i])
	break;

      // Not in order
      if (gram[i] < m_last_gram[i]) {
	fprintf(stderr, "TreeGram::check_order(): "
		"gram not in sorted order\n");
	print_gram(stderr, gram);
	exit(1);
      }
    }

    // Duplicate?
    if (i == gram.size()) {
      fprintf(stderr, "TreeGram::check_order(): "
	      "duplicate gram\n");
      print_gram(stderr, gram);
      exit(1);
    }
  }
}

// Note that 'last' is not included in the range.
int
TreeGram::binary_search(int word, int first, int last)
{
  int middle;
  int half;

  int len = last - first;

  while (len > 5) { // FIXME: magic threshold to do linear search
    half = len / 2;
    middle = first + half;

    // Equal
    if (m_nodes[middle].word == word)
      return middle;

    // First half
    if (m_nodes[middle].word > word) {
      last = middle;
      len = last - first;
    }

    // Second half
    else {
      first = middle + 1;
      len = last - first;
    }
  }

  while (first < last) {
    if (m_nodes[first].word == word)
      return first;
    first++;
  }

  return -1;
}

// Returns unigram if node_index < 0
int
TreeGram::find_child(int word, int node_index)
{
  if (word < 0 || word >= m_words.size()) {
    fprintf(stderr, "TreeGram::find_child(): "
	    "index %d out of vocabulary size %d\n", word, m_words.size());
    exit(1);
  }

  if (node_index < 0)
    return word;

  assert(node_index < m_nodes.size() - 1);

  int first = m_nodes[node_index].child_index;
  int last = m_nodes[node_index + 1].child_index; // not included
  if (first < 0 || last < 0)
    return -1;

  return binary_search(word, first, last);
}

/// Finds the path to the current gram.
//
// PRECONDITIONS:
// - m_insert_stack contains the indices of 'm_last_gram'
//
// POSTCONDITIONS:
// - m_insert_stack contains the indices of 'gram' without the last word
void
TreeGram::find_path(const Gram &gram)
{
  int prev = -1;
  int order = 0;
  int index;

  assert(gram.size() > 1);

  // The beginning of the path can be found quickly by using the index
  // stack.
  while (1) {
    assert(order < m_last_gram.size() - 1);
    if (gram[order] != m_last_gram[order])
      break;
    order++;
  }
  m_insert_stack.resize(order);

  // The rest of the path must be searched.
  order--;
  if (order < 0)
    prev = -1;
  else
    prev = m_insert_stack[order];

  while (order < m_last_gram.size() - 1) {
    index = find_child(gram[order], prev);
    if (index < 0) {
      fprintf(stderr, "prefix not found\n");
      print_gram(stderr, gram);
      exit(1);
    }

    m_insert_stack.push_back(index);

    prev = index;
    order++;
  }
}

void
TreeGram::add_gram(const Gram &gram, float log_prob, float back_off)
{
  if (m_nodes.empty()) {
    fprintf(stderr, "TreeGram::add_gram(): "
	    "nodes must be reserved before calling this function\n");
    exit(1);
  }

  check_order(gram);

  // Update order counts
  if (gram.size() == m_last_gram.size() + 1) {
    m_order_count.push_back(0);
    m_order++;
  }
  assert(m_order_count.size() == gram.size());
  m_order_count[gram.size()]++;

  // Handle unigrams separately
  if (gram.size() == 1) {

    // OOV can be updated anytime.
    if (gram[0] == 0) {
      m_nodes[0].log_prob = log_prob;
      m_nodes[0].back_off = back_off;
    }

    // Unigram which is not OOV
    else
      m_nodes.push_back(Node(gram[0], log_prob, back_off, -1));
  }

  // 2-grams or higher
  else {
    // Update the path
    find_path(gram);

    if (m_nodes[m_insert_stack.back()].child_index < 0)
      m_nodes[m_insert_stack.back()].child_index = m_nodes.size();

    m_nodes.push_back(Node(gram.back(), log_prob, back_off, -1));
    m_nodes[m_insert_stack.back() + 1].child_index = m_nodes.size();
  }

  m_last_gram = gram;
  assert(m_order == m_last_gram.size());
}

void
TreeGram::write(FILE *file, bool reflip)
{
  fputs(format_str.c_str(), file);

  // Write type and interpolation weights
  if (m_type == BACKOFF)
    fputs("backoff\n", file);
  else if (m_type == INTERPOLATED)
    fputs("interpolated\n", file);

  fprintf(file, "%d\n", num_words());
  for (int i = 0; i < num_words(); i++)
    fprintf(file, "%s\n", word(i).c_str());
  fprintf(file, "%d %d\n", m_order, m_nodes.size());

  // Use correct endianity
  if (Endian::big)
    flip_endian();

  // Write possible interpolation weights
  if (m_type == INTERPOLATED) {
    assert(m_interpolation.size() == m_order);
    fwrite(&m_interpolation[0], m_order * sizeof(m_interpolation[0]), 1, file);
  }

  // Write nodes
  fwrite(&m_nodes[0], m_nodes.size() * sizeof(TreeGram::Node), 1, file);

  if (ferror(file)) {
    fprintf(stderr, "TreeGram::write(): write error: %s\n", strerror(errno));
    exit(1);
  }

  // Restore to original endianess
  if (Endian::big && reflip)
    flip_endian();
}

void
TreeGram::read(FILE *file)
{
  std::string line;
  int words;
  bool ret;

  // Read the header
  ret = read_string(&line, format_str.length(), file);
  if (!ret || line != format_str) {
    fprintf(stderr, "TreeGram::read(): invalid file format\n");
    exit(1);
  }

  // Read LM type
  read_line(&line, file);
  chomp(&line);
  if (line == "backoff")
    m_type = BACKOFF;
  else if (line == "interpolated")
    m_type = INTERPOLATED;
  else {
    fprintf(stderr, "TreeGram::read(): invalid type: %s\n", line.c_str());
    exit(1);
  }

  // Read the number of words
  if (!read_line(&line, file)) {
    fprintf(stderr, "TreeGram::read(): unexpected end of file\n");
    exit(1);
  }
  words = atoi(line.c_str());
  if (words < 1) {
    fprintf(stderr, "TreeGram::read(): invalid number of words: %s\n",
	    line.c_str());
    exit(1);
  }

  // Read the vocabulary
  for (int i=0; i < words; i++) {
    if (!read_line(&line, file)) {
      fprintf(stderr, "TreeGram::read(): "
	      "read error while reading vocabulary\n");
      exit(1);
    }
    chomp(&line);
    add_word(line);
  }

  // Read the order and the number of nodes
  int m_nodes_size;
  fscanf(file, "%d %d\n", &m_order, &m_nodes_size);
  reserve_nodes(m_nodes_size);

  // Read the possible interpolation weights
  if (m_type == INTERPOLATED) {
    m_interpolation.resize(m_order);
    fread(&m_interpolation[0], sizeof(float) * m_order, 1, file);
  }

  // Read the nodes
  size_t block_size = m_nodes.size() * sizeof(TreeGram::Node);
  size_t blocks_read = fread(&m_nodes[0], block_size, 1, file);
  if (blocks_read != 1) {
      fprintf(stderr, "TreeGram::read(): "
	      "read error while reading ngrams\n");
      exit(1);
  }

  if (Endian::big)
    flip_endian();
}

void
TreeGram::flip_endian()
{
  assert(sizeof(m_nodes[0].word == 4));
  assert(sizeof(m_nodes[0].log_prob == 4));
  assert(sizeof(m_nodes[0].back_off == 4));
  assert(sizeof(m_nodes[0].child_index == 4));

  if (m_type == INTERPOLATED) {
    assert(m_interpolation.size() == m_order);
    Endian::convert(&m_interpolation[0], 4 * m_order);
  }

  for (int i = 0; i < m_nodes.size(); i++) {
    Endian::convert(&m_nodes[i].word, 4);
    Endian::convert(&m_nodes[i].log_prob, 4);
    Endian::convert(&m_nodes[i].back_off, 4);
    Endian::convert(&m_nodes[i].child_index, 4);
  }
}

// Fetch the node indices of the requested gram to m_fetch_stack as
// far as found in the tree structure.
void
TreeGram::fetch_gram(const Gram &gram, int first)
{
  int prev = -1;
  m_fetch_stack.clear();

  while (m_fetch_stack.size() < gram.size()) {
    int node = find_child(gram[first], prev);
    if (node < 0)
      break;
    m_fetch_stack.push_back(node);
    first++;
    node = prev;
  }
}

float
TreeGram::log_prob(const Gram &gram)
{
  assert(gram.size() > 0);

  float log_prob = 0;

  // Denote by (w(1) w(2) ... w(N)) the ngram that was requested.  The
  // log-probability of the back-off model is computed as follows:

  // Iterate n = 1..N:
  // - If (w(n) ... w(N)) not found, add the possible (w(n) ... w(N-1) backoff
  // - Otherwise, add the log-prob and return.
  int n = 0;
  while (1) {
    assert(n < gram.size());
    fetch_gram(gram, n);
    assert(m_fetch_stack.size() > 0);

    // Full gram found?
    if (m_fetch_stack.size() == gram.size()) {
      log_prob += m_nodes[m_fetch_stack.back()].log_prob;
      m_last_order = gram.size() - n;
      break;
    }

    // Back-off found?
    if (m_fetch_stack.size() == gram.size() - 1)
      log_prob += m_nodes[m_fetch_stack.back()].back_off;

    n++;
  }

  return log_prob;
}

TreeGram::Iterator::Iterator(TreeGram *gram)
  : m_gram(gram)
{
  if (gram)
    reset(gram);
}

void
TreeGram::Iterator::reset(TreeGram *gram)
{
  assert(gram);
  m_gram = gram;
  m_index_stack.clear();
  m_index_stack.resize(gram->m_order);
}

bool
TreeGram::Iterator::next()
{
  bool backtrack = false;

  // Start the search
  if (m_index_stack.empty()) {
    m_index_stack.push_back(0);
    return true;
  }

  // Go to the next node.  Backtrack if necessary.
  while (1) {
    assert(!m_index_stack.empty());
    int index = m_index_stack.back();
    TreeGram::Node *node = &m_gram->m_nodes[index];

    // End of the structure?
    if (index == m_gram->m_nodes.size() - 1)
      return false;

    // If not backtracking, try diving deeper
    if (!backtrack) {
      // Do we have children?
      if (node->child_index > 0 && (node+1)->child_index > 0) {
	m_index_stack.push_back(node->child_index);
	return true;
      }
    }
    backtrack = false;

    // No children, try siblings
    if (m_index_stack.size() == 1) {
      // Unigram level: we have always siblings
      index++;
      assert(index < m_gram->m_order_count[0]);
      return true;
    }
    else {
      // Higher order
      m_index_stack.pop_back();
      TreeGram::Node *parent = &m_gram->m_nodes[m_index_stack.back()];

      // Do we have more siblings?
      index++;
      if (index < (parent+1)->child_index) {
	m_index_stack.push_back(index);
	return true;
      }

      // No more siblings, backtrack.
      backtrack = true;
    }
  }
}

bool
TreeGram::Iterator::next_order(int order)
{
  if (order < 1 || order > m_gram->m_order) {
    fprintf(stderr, "TreeGram::Iterator::next_order(): invalid order %d\n",
	    order);
    exit(1);
  }

  while (1) {
    if (!next())
      return false;

    if (m_index_stack.size() == order)
      return true;
  }
}

const TreeGram::Node&
TreeGram::Iterator::node()
{
  assert(m_gram);
  assert(!m_index_stack.empty());

  return m_gram->m_nodes[m_index_stack.back()];
}
<|endoftext|>


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

  Program:   Visualization Library
  Module:    VoxelMod.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

This file is part of the Visualization Library. No part of this file or its
contents may be copied, reproduced or altered in any way without the express
written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
#include <math.h>
#include "VoxelMod.hh"
#include "BScalars.hh"

vlVoxelModeller::vlVoxelModeller()
{
  this->MaximumDistance = 1.0;

  this->ModelBounds[0] = 0.0;
  this->ModelBounds[1] = 0.0;
  this->ModelBounds[2] = 0.0;
  this->ModelBounds[3] = 0.0;
  this->ModelBounds[4] = 0.0;
  this->ModelBounds[5] = 0.0;

  this->SampleDimensions[0] = 50;
  this->SampleDimensions[1] = 50;
  this->SampleDimensions[2] = 50;
}

void vlVoxelModeller::PrintSelf(ostream& os, vlIndent indent)
{
  if (this->ShouldIPrint(vlVoxelModeller::GetClassName()))
    {
    vlDataSetToStructuredPointsFilter::PrintSelf(os,indent);

    os << indent << "Maximum Distance: " << this->MaximumDistance << "\n";
    os << indent << "Sample Dimensions: (" << this->SampleDimensions[0] << ", "
                 << this->SampleDimensions[1] << ", "
                 << this->SampleDimensions[2] << ")\n";
    os << indent << "Model Bounds: \n";
    os << indent << "  Xmin,Xmax: (" << this->ModelBounds[0] << ", " << this->ModelBounds[1] << ")\n";
    os << indent << "  Ymin,Ymax: (" << this->ModelBounds[2] << ", " << this->ModelBounds[3] << ")\n";
    os << indent << "  Zmin,Zmax: (" << this->ModelBounds[4] << ", " << this->ModelBounds[5] << ")\n";
    }
}

void vlVoxelModeller::SetModelBounds(float *bounds)
{
  vlVoxelModeller::SetModelBounds(bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5]);
}

void vlVoxelModeller::SetModelBounds(float xmin, float xmax, float ymin, float ymax, float zmin, float zmax)
{
  if (this->ModelBounds[0] != xmin || this->ModelBounds[1] != xmax ||
  this->ModelBounds[2] != ymin || this->ModelBounds[3] != ymax ||
  this->ModelBounds[4] != zmin || this->ModelBounds[5] != zmax )
    {
    float length;

    this->Modified();
    this->ModelBounds[0] = xmin;
    this->ModelBounds[1] = xmax;
    this->ModelBounds[2] = ymin;
    this->ModelBounds[3] = ymax;
    this->ModelBounds[4] = zmin;
    this->ModelBounds[5] = zmax;

    this->Origin[0] = xmin;
    this->Origin[1] = ymin;
    this->Origin[2] = zmin;

    if ( (length = xmin - xmax) == 0.0 ) length = 1.0;
    this->AspectRatio[0] = 1.0;
    this->AspectRatio[1] = (ymax - ymin) / length;
    this->AspectRatio[2] = (zmax - zmin) / length;
    }
}

void vlVoxelModeller::Execute()
{
  int cellNum, i, j, k;
  float *bounds, adjBounds[6];
  vlCell *cell;
  float maxDistance, pcoords[3];
  vlBitScalars *newScalars;
  int numPts, idx;
  int subId;
  int min[3], max[3];
  float x[3], prevDistance2, distance2;
  int jkFactor;
  float weights[MAX_CELL_SIZE];
  float closestPoint[3];
  float voxelHalfWidth[3];

  vlDebugMacro(<< "Executing Voxel model");
//
// Initialize self; create output objects
//
  this->Initialize();

  numPts = this->SampleDimensions[0] * this->SampleDimensions[1] * this->SampleDimensions[2];
  newScalars = new vlBitScalars(numPts);
  for (i=0; i<numPts; i++) newScalars->SetScalar(i,0);

  this->SetDimensions(this->GetSampleDimensions());
  maxDistance = this->ComputeModelBounds();
//
// Voxel widths are 1/2 the height, width, length of a voxel
//
  for (i=0; i < 3; i++) voxelHalfWidth[i] = this->AspectRatio[i] / 2.0;
//
// Traverse all cells; computing distance function on volume points.
//
  for (cellNum=0; cellNum < this->Input->GetNumberOfCells(); cellNum++)
    {
    cell = this->Input->GetCell(cellNum);
    bounds = cell->GetBounds();
    for (i=0; i<3; i++)
      {
      adjBounds[2*i] = bounds[2*i] - maxDistance;
      adjBounds[2*i+1] = bounds[2*i+1] + maxDistance;
      }

    // compute dimensional bounds in data set
    for (i=0; i<3; i++)
      {
      min[i] = (adjBounds[2*i] - this->Origin[i]) / this->AspectRatio[i];
      max[i] = (adjBounds[2*i+1] - this->Origin[i]) / this->AspectRatio[i];
      if (min[i] < 0) min[i] = 0;
      if (max[i] >= this->SampleDimensions[i]) max[i] = this->SampleDimensions[i] - 1;
      }

    jkFactor = this->SampleDimensions[0]*this->SampleDimensions[1];
    for (k = min[2]; k <= max[2]; k++)
      {
      x[2] = this->AspectRatio[2] * k + this->Origin[2];
      for (j = min[1]; j <= max[1]; j++)
        {
        x[1] = this->AspectRatio[1] * j + this->Origin[1];
        for (i = min[0]; i <= max[0]; i++)
          {
	  idx = jkFactor*k + this->SampleDimensions[0]*j + i;
	  if (!(newScalars->GetScalar(idx)))
	    {
	    x[0] = this->AspectRatio[0] * i + this->Origin[0];
	    cell->EvaluatePosition(x, closestPoint, subId, pcoords,
                                   distance2, weights);
	    if ( closestPoint[0] <= voxelHalfWidth[0] ||
            closestPoint[1] <= voxelHalfWidth[1] ||
            closestPoint[2] <= voxelHalfWidth[2] )
	      newScalars->SetScalar(idx,1);
	    }
	  }
        }
      }
    }
//
// Update self
//
  this->PointData.SetScalars(newScalars);

}

float vlVoxelModeller::ComputeModelBounds()
{
  float *bounds, maxDist;
  int i, adjustBounds=0;

  // compute model bounds if not set previously
  if ( this->ModelBounds[0] >= this->ModelBounds[1] ||
  this->ModelBounds[2] >= this->ModelBounds[3] ||
  this->ModelBounds[4] >= this->ModelBounds[5] )
    {
    adjustBounds = 1;
    bounds = this->Input->GetBounds();
    }
  else
    {
    bounds = this->ModelBounds;
    }

  for (maxDist=0.0, i=0; i<3; i++)
    if ( (bounds[2*i+1] - bounds[2*i]) > maxDist )
      maxDist = bounds[2*i+1] - bounds[2*i];

  maxDist *= this->MaximumDistance;

  // adjust bounds so model fits strictly inside (only if not set previously)
  if ( adjustBounds )
    {
    for (i=0; i<3; i++)
      {
      this->ModelBounds[2*i] = bounds[2*i] - maxDist;
      this->ModelBounds[2*i+1] = bounds[2*i+1] + maxDist;
      }
    }

  // Set volume origin and aspect ratio
  for (i=0; i<3; i++)
    {
    this->Origin[i] = this->ModelBounds[2*i];
    this->AspectRatio[i] = (this->ModelBounds[2*i+1] - this->ModelBounds[2*i])/
      (this->SampleDimensions[i] - 1);
    }

  return maxDist;
}

void vlVoxelModeller::SetSampleDimensions(int i, int j, int k)
{
  int dim[3];

  dim[0] = i;
  dim[1] = j;
  dim[2] = k;

  this->SetSampleDimensions(dim);
}

void vlVoxelModeller::SetSampleDimensions(int dim[3])
{
  vlDebugMacro(<< " setting SampleDimensions to (" << dim[0] << "," << dim[1] << "," << dim[2] << ")");

  if ( dim[0] != this->SampleDimensions[0] || dim[1] != SampleDimensions[1] ||
  dim[2] != SampleDimensions[2] )
    {
    if ( dim[0]<1 || dim[1]<1 || dim[2]<1 )
      {
      vlErrorMacro (<< "Bad Sample Dimensions, retaining previous values");
      return;
      }

    for (int dataDim=0, i=0; i<3 ; i++) if (dim[i] > 1) dataDim++;

    if ( dataDim  < 3 )
      {
      vlErrorMacro(<<"Sample dimensions must define a volume!");
      return;
      }

    for ( i=0; i<3; i++) this->SampleDimensions[i] = dim[i];

    this->Modified();
    }
}
<commit_msg>added write method<commit_after>/*=========================================================================

  Program:   Visualization Library
  Module:    VoxelMod.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

This file is part of the Visualization Library. No part of this file or its
contents may be copied, reproduced or altered in any way without the express
written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
#include <math.h>
#include <stdio.h>
#include "VoxelMod.hh"
#include "BScalars.hh"

vlVoxelModeller::vlVoxelModeller()
{
  this->MaximumDistance = 1.0;

  this->ModelBounds[0] = 0.0;
  this->ModelBounds[1] = 0.0;
  this->ModelBounds[2] = 0.0;
  this->ModelBounds[3] = 0.0;
  this->ModelBounds[4] = 0.0;
  this->ModelBounds[5] = 0.0;

  this->SampleDimensions[0] = 50;
  this->SampleDimensions[1] = 50;
  this->SampleDimensions[2] = 50;
}

void vlVoxelModeller::PrintSelf(ostream& os, vlIndent indent)
{
  if (this->ShouldIPrint(vlVoxelModeller::GetClassName()))
    {
    vlDataSetToStructuredPointsFilter::PrintSelf(os,indent);

    os << indent << "Maximum Distance: " << this->MaximumDistance << "\n";
    os << indent << "Sample Dimensions: (" << this->SampleDimensions[0] << ", "
                 << this->SampleDimensions[1] << ", "
                 << this->SampleDimensions[2] << ")\n";
    os << indent << "Model Bounds: \n";
    os << indent << "  Xmin,Xmax: (" << this->ModelBounds[0] << ", " << this->ModelBounds[1] << ")\n";
    os << indent << "  Ymin,Ymax: (" << this->ModelBounds[2] << ", " << this->ModelBounds[3] << ")\n";
    os << indent << "  Zmin,Zmax: (" << this->ModelBounds[4] << ", " << this->ModelBounds[5] << ")\n";
    }
}

void vlVoxelModeller::SetModelBounds(float *bounds)
{
  vlVoxelModeller::SetModelBounds(bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5]);
}

void vlVoxelModeller::SetModelBounds(float xmin, float xmax, float ymin, float ymax, float zmin, float zmax)
{
  if (this->ModelBounds[0] != xmin || this->ModelBounds[1] != xmax ||
  this->ModelBounds[2] != ymin || this->ModelBounds[3] != ymax ||
  this->ModelBounds[4] != zmin || this->ModelBounds[5] != zmax )
    {
    float length;

    this->Modified();
    this->ModelBounds[0] = xmin;
    this->ModelBounds[1] = xmax;
    this->ModelBounds[2] = ymin;
    this->ModelBounds[3] = ymax;
    this->ModelBounds[4] = zmin;
    this->ModelBounds[5] = zmax;

    this->Origin[0] = xmin;
    this->Origin[1] = ymin;
    this->Origin[2] = zmin;

    if ( (length = xmax - xmin) == 0.0 ) length = 1.0;
    this->AspectRatio[0] = 1.0;
    this->AspectRatio[1] = (ymax - ymin) / length;
    this->AspectRatio[2] = (zmax - zmin) / length;
    }
}

void vlVoxelModeller::Execute()
{
  int cellNum, i, j, k;
  float *bounds, adjBounds[6];
  vlCell *cell;
  float maxDistance, pcoords[3];
  vlBitScalars *newScalars;
  int numPts, idx;
  int subId;
  int min[3], max[3];
  float x[3], prevDistance2, distance2;
  int jkFactor;
  float weights[MAX_CELL_SIZE];
  float closestPoint[3];
  float voxelHalfWidth[3];

  vlDebugMacro(<< "Executing Voxel model");
//
// Initialize self; create output objects
//
  this->Initialize();

  numPts = this->SampleDimensions[0] * this->SampleDimensions[1] * this->SampleDimensions[2];
  newScalars = new vlBitScalars(numPts);
  for (i=0; i<numPts; i++) newScalars->SetScalar(i,0);

  this->SetDimensions(this->GetSampleDimensions());
  maxDistance = this->ComputeModelBounds();
//
// Voxel widths are 1/2 the height, width, length of a voxel
//
  for (i=0; i < 3; i++) voxelHalfWidth[i] = this->AspectRatio[i] / 2.0;
//
// Traverse all cells; computing distance function on volume points.
//
  for (cellNum=0; cellNum < this->Input->GetNumberOfCells(); cellNum++)
    {
    cell = this->Input->GetCell(cellNum);
    bounds = cell->GetBounds();
    for (i=0; i<3; i++)
      {
      adjBounds[2*i] = bounds[2*i] - maxDistance;
      adjBounds[2*i+1] = bounds[2*i+1] + maxDistance;
      }

    // compute dimensional bounds in data set
    for (i=0; i<3; i++)
      {
      min[i] = (adjBounds[2*i] - this->Origin[i]) / this->AspectRatio[i];
      max[i] = (adjBounds[2*i+1] - this->Origin[i]) / this->AspectRatio[i];
      if (min[i] < 0) min[i] = 0;
      if (max[i] >= this->SampleDimensions[i]) max[i] = this->SampleDimensions[i] - 1;
      }

    jkFactor = this->SampleDimensions[0]*this->SampleDimensions[1];
    for (k = min[2]; k <= max[2]; k++)
      {
      x[2] = this->AspectRatio[2] * k + this->Origin[2];
      for (j = min[1]; j <= max[1]; j++)
        {
        x[1] = this->AspectRatio[1] * j + this->Origin[1];
        for (i = min[0]; i <= max[0]; i++)
          {
	  idx = jkFactor*k + this->SampleDimensions[0]*j + i;
	  if (!(newScalars->GetScalar(idx)))
	    {
	    x[0] = this->AspectRatio[0] * i + this->Origin[0];
	    cell->EvaluatePosition(x, closestPoint, subId, pcoords,
                                   distance2, weights);
	    if ((fabs(closestPoint[0] - x[0]) <= voxelHalfWidth[0]) &&
		(fabs(closestPoint[1] - x[1]) <= voxelHalfWidth[1]) &&
		(fabs(closestPoint[2] - x[2]) <= voxelHalfWidth[2]))
	      {
	      newScalars->SetScalar(idx,1);
	      }
	    }
	  }
        }
      }
    }
//
// Update self
//
  this->PointData.SetScalars(newScalars);

}

float vlVoxelModeller::ComputeModelBounds()
{
  float *bounds, maxDist;
  int i, adjustBounds=0;

  // compute model bounds if not set previously
  if ( this->ModelBounds[0] >= this->ModelBounds[1] ||
  this->ModelBounds[2] >= this->ModelBounds[3] ||
  this->ModelBounds[4] >= this->ModelBounds[5] )
    {
    adjustBounds = 1;
    bounds = this->Input->GetBounds();
    }
  else
    {
    bounds = this->ModelBounds;
    }

  for (maxDist=0.0, i=0; i<3; i++)
    if ( (bounds[2*i+1] - bounds[2*i]) > maxDist )
      maxDist = bounds[2*i+1] - bounds[2*i];

  maxDist *= this->MaximumDistance;

  // adjust bounds so model fits strictly inside (only if not set previously)
  if ( adjustBounds )
    {
    for (i=0; i<3; i++)
      {
      this->ModelBounds[2*i] = bounds[2*i] - maxDist;
      this->ModelBounds[2*i+1] = bounds[2*i+1] + maxDist;
      }
    }

  // Set volume origin and aspect ratio
  for (i=0; i<3; i++)
    {
    this->Origin[i] = this->ModelBounds[2*i];
    this->AspectRatio[i] = (this->ModelBounds[2*i+1] - this->ModelBounds[2*i])/
      (this->SampleDimensions[i] - 1);
    }

  return maxDist;
}

void vlVoxelModeller::SetSampleDimensions(int i, int j, int k)
{
  int dim[3];

  dim[0] = i;
  dim[1] = j;
  dim[2] = k;

  this->SetSampleDimensions(dim);
}

void vlVoxelModeller::SetSampleDimensions(int dim[3])
{
  vlDebugMacro(<< " setting SampleDimensions to (" << dim[0] << "," << dim[1] << "," << dim[2] << ")");

  if ( dim[0] != this->SampleDimensions[0] || dim[1] != SampleDimensions[1] ||
  dim[2] != SampleDimensions[2] )
    {
    if ( dim[0]<1 || dim[1]<1 || dim[2]<1 )
      {
      vlErrorMacro (<< "Bad Sample Dimensions, retaining previous values");
      return;
      }

    for (int dataDim=0, i=0; i<3 ; i++) if (dim[i] > 1) dataDim++;

    if ( dataDim  < 3 )
      {
      vlErrorMacro(<<"Sample dimensions must define a volume!");
      return;
      }

    for ( i=0; i<3; i++) this->SampleDimensions[i] = dim[i];

    this->Modified();
    }
}

void vlVoxelModeller::Write(char *fname)
{
  FILE *fp;
  int cellNum, i, j, k;
  float *bounds;
  float maxDistance;
  vlBitScalars *newScalars;
  int numPts, idx;
  int bitcount;
  unsigned char uc;

  vlDebugMacro(<< "Writing Voxel model");

  // update the data
  this->Execute();

  numPts = this->SampleDimensions[0] * this->SampleDimensions[1] * this->SampleDimensions[2];

  newScalars = (vlBitScalars *)this->PointData.GetScalars();

  this->SetDimensions(this->GetSampleDimensions());
  maxDistance = this->ComputeModelBounds();

  fp = fopen(fname,"w");
  if (!fp)
    {
    vlErrorMacro(<< "Couldn't open file: " << fname << endl);
    return;
    }

  fprintf(fp,"Voxel Data File\n");
  fprintf(fp,"Origin: %f %f %f\n",this->Origin[0],
	  this->Origin[1],this->Origin[2]);
  fprintf(fp,"Aspect: %f %f %f\n",this->AspectRatio[0],
	  this->AspectRatio[1],this->AspectRatio[2]);
  fprintf(fp,"Dimensions: %i %i %i\n",this->SampleDimensions[0],
	  this->SampleDimensions[1],this->SampleDimensions[2]);

  // write out the data
  bitcount = 0;
  idx = 0;
  uc = 0x00;

  for (k = 0; k < this->SampleDimensions[2]; k++)
    for (j = 0; j < this->SampleDimensions[1]; j++)
      for (i = 0; i < this->SampleDimensions[0]; i++)
	{
	if (newScalars->GetScalar(idx))
	  {
	  uc |= (0x80 >> bitcount);
	  }
	bitcount++;
	if (bitcount == 8)
	  {
	  fputc(uc,fp);
	  uc = 0x00;
	  bitcount = 0;
	  }
	idx++;
	}
  if (bitcount)
    {
    fputc(uc,fp);
    }

  fclose(fp);
}
<|endoftext|>


<commit_before>/****************************************************************************
 Copyright (c) 2015 Sérgio Vieira - sergiosvieira@gmail.com

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 ****************************************************************************/

#include "YObject.h"

/** YDA **/
#include "YSprite.h"

/** C++ **/
#include <cassert>

/** SDL2 **/
#include <SDL.h>
#include <SDL2_image/SDL_image.h>

/** Public Methods **/
void YObject::render(SDL_Renderer* a_renderer) const
{
    assert(a_renderer != nullptr);
    assert(m_sprite != nullptr);

    SDL_Rect srcRect = m_sprite->rect();
    SDL_Rect dstRect;

    dstRect.x = m_position.x();
    dstRect.y = m_position.y();
    dstRect.w = m_sprite->width();
    dstRect.h = m_sprite->height();

    SDL_RenderCopy(a_renderer,
                   m_sprite->texture(),
                   &srcRect,
                   &dstRect);
}

YPoint YObject::position() const
{
	return m_position;
}

void YObject::position(YPoint a_position)
{
	m_position = a_position;
}

YPoint YObject::anchor() const
{
	return m_anchor;
}

void YObject::anchor(YPoint a_anchor)
{
	m_anchor = a_anchor;
}

void YObject::visible(bool a_value)
{
	m_visible = a_value;
}

bool YObject::isVisible() const
{
	return m_visible;
}

YSprite* YObject::sprite() const
{
    return m_sprite;
}<commit_msg>Adds algorithm include (visual studio compability)<commit_after>/****************************************************************************
 Copyright (c) 2015 Sérgio Vieira - sergiosvieira@gmail.com

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 ****************************************************************************/

#include "YObject.h"

/** YDA **/
#include "YSprite.h"

/** C++ **/
#include <cassert>

/** SDL2 **/
#include <SDL.h>
#ifdef WIN32
	#include <SDL_image.h>
#else
	#include <SDL2_image/SDL_image.h>
#endif

/** Public Methods **/
void YObject::render(SDL_Renderer* a_renderer) const
{
    assert(a_renderer != nullptr);
    assert(m_sprite != nullptr);

    SDL_Rect srcRect = m_sprite->rect();
    SDL_Rect dstRect;

    dstRect.x = m_position.x();
    dstRect.y = m_position.y();
    dstRect.w = m_sprite->width();
    dstRect.h = m_sprite->height();

    SDL_RenderCopy(a_renderer,
                   m_sprite->texture(),
                   &srcRect,
                   &dstRect);
}

YPoint YObject::position() const
{
	return m_position;
}

void YObject::position(YPoint a_position)
{
	m_position = a_position;
}

YPoint YObject::anchor() const
{
	return m_anchor;
}

void YObject::anchor(YPoint a_anchor)
{
	m_anchor = a_anchor;
}

void YObject::visible(bool a_value)
{
	m_visible = a_value;
}

bool YObject::isVisible() const
{
	return m_visible;
}

YSprite* YObject::sprite() const
{
    return m_sprite;
}<|endoftext|>


<commit_before>#include <plasp/utils/Parser.h>

#include <algorithm>

#include <boost/assert.hpp>

#include <plasp/utils/ParserException.h>

namespace plasp
{
namespace utils
{

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Parser
//
////////////////////////////////////////////////////////////////////////////////////////////////////

const std::istreambuf_iterator<char> Parser::EndOfFile = std::istreambuf_iterator<char>();

////////////////////////////////////////////////////////////////////////////////////////////////////

Parser::Parser(std::istream &istream)
:	m_istream(istream),
	m_position(m_istream),
	m_row{1},
	m_column{1},
	m_endOfFile{false}
{
	std::setlocale(LC_NUMERIC, "C");

	// Don’t skip whitespace
	istream.exceptions(std::istream::badbit);

	checkStream();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

size_t Parser::row() const
{
	return m_row;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

size_t Parser::column() const
{
	return m_column;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

char Parser::currentCharacter() const
{
	checkStream();

	return *m_position;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

bool Parser::atEndOfFile() const
{
	return m_position.equal(EndOfFile);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void Parser::checkStream() const
{
	if (atEndOfFile())
		throw ParserException(m_row, m_column, "Reading past end of file");

	if (m_istream.fail())
		throw ParserException(m_row, m_column);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void Parser::advance()
{
	checkStream();

	const auto character = currentCharacter();

	if (character == '\n')
	{
		m_row++;
		m_column = 1;
	}
	else if (std::isblank(character) || std::isprint(character))
		m_column++;

	m_position++;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

bool Parser::advanceIf(char expectedCharacter)
{
	checkStream();

	if (currentCharacter() != expectedCharacter)
		return false;

	advance();

	return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void Parser::skipWhiteSpace()
{
	return skipWhiteSpace(
		[](const auto character)
		{
			return std::isspace(character);
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void Parser::skipLine()
{
	checkStream();

	while (currentCharacter() != '\n')
		advance();

	advance();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

std::string Parser::getLine()
{
	checkStream();

	std::string value;

	while (true)
	{
		const auto character = currentCharacter();

		advance();

		if (character == '\n')
			break;
		else if (character == '\r')
			continue;

		value.push_back(character);
	}

	return value;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
std::string Parser::parse<std::string>()
{
	skipWhiteSpace();

	std::string value;

	while (true)
	{
		const auto character = currentCharacter();

		if (std::isspace(character))
			break;

		value.push_back(character);
		advance();
	}

	return value;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<std::string>(const std::string &expectedValue)
{
	BOOST_ASSERT(!std::isspace(expectedValue[0]));

	skipWhiteSpace();

	std::for_each(expectedValue.cbegin(), expectedValue.cend(),
		[&](const auto &expectedCharacter)
		{
			const auto character = static_cast<char>(this->currentCharacter());

			if (character != expectedCharacter)
				throw ParserException(m_row, m_column, "Unexpected string, expected " + expectedValue + " (expected " + expectedCharacter + ", got " + character + ")");

			this->advance();
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

uint64_t Parser::parseIntegerBody()
{
	checkStream();

	if (!std::isdigit(currentCharacter()))
		throw ParserException(m_row, m_column, "Could not parse integer value");

	uint64_t value = 0;

	while (!atEndOfFile())
	{
		const auto character = currentCharacter();

		if (!std::isdigit(character))
			break;

		value *= 10;
		value += character - '0';

		advance();
	}

	return value;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
int64_t Parser::parse<int64_t>()
{
	skipWhiteSpace();

	bool positive = advanceIf('+') || !advanceIf('-');

	const auto value = parseIntegerBody();

	return (positive ? value : -value);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
uint64_t Parser::parse<uint64_t>()
{
	skipWhiteSpace();

	if (currentCharacter() == '-')
		throw ParserException(m_row, m_column, "Expected unsigned integer, got signed one");

	return parseIntegerBody();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<int64_t>(const int64_t &expectedValue)
{
	const auto value = parse<int64_t>();

	if (value != expectedValue)
		throw ParserException(m_row, m_column, "Unexpected value " + std::to_string(value) + ", expected " + std::to_string(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<uint64_t>(const uint64_t &expectedValue)
{
	const auto value = parse<uint64_t>();

	if (value != expectedValue)
		throw ParserException(m_row, m_column, "Unexpected value " + std::to_string(value) + ", expected " + std::to_string(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
int32_t Parser::parse<int32_t>()
{
	return static_cast<int32_t>(parse<int64_t>());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
uint32_t Parser::parse<uint32_t>()
{
	return static_cast<uint32_t>(parse<uint64_t>());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<int32_t>(const int32_t &expectedValue)
{
	expect<int64_t>(static_cast<int64_t>(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<uint32_t>(const uint32_t &expectedValue)
{
	expect<uint64_t>(static_cast<uint64_t>(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
int16_t Parser::parse<int16_t>()
{
	return static_cast<int16_t>(parse<int64_t>());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
uint16_t Parser::parse<uint16_t>()
{
	return static_cast<uint16_t>(parse<uint64_t>());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<int16_t>(const int16_t &expectedValue)
{
	expect<int64_t>(static_cast<int64_t>(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<uint16_t>(const uint16_t &expectedValue)
{
	expect<uint64_t>(static_cast<uint64_t>(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
int8_t Parser::parse<int8_t>()
{
	return static_cast<int8_t>(parse<int64_t>());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
uint8_t Parser::parse<uint8_t>()
{
	return static_cast<uint8_t>(parse<uint64_t>());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<int8_t>(const int8_t &expectedValue)
{
	expect<int64_t>(static_cast<int64_t>(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<uint8_t>(const uint8_t &expectedValue)
{
	expect<uint64_t>(static_cast<uint64_t>(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
bool Parser::parse<bool>()
{
	skipWhiteSpace();

	if (advanceIf('0'))
	    return false;

	if (advanceIf('1'))
		return true;

	throw ParserException(m_row, m_column, "Could not parse Boolean value");
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<bool>(const bool &expectedValue)
{
	const auto value = parse<bool>();

	if (value != expectedValue)
		throw ParserException(m_row, m_column, "Unexpected value " + std::to_string(value) + ", expected " + std::to_string(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

}
}
<commit_msg>Minor formatting.<commit_after>#include <plasp/utils/Parser.h>

#include <algorithm>

#include <boost/assert.hpp>

#include <plasp/utils/ParserException.h>

namespace plasp
{
namespace utils
{

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Parser
//
////////////////////////////////////////////////////////////////////////////////////////////////////

const std::istreambuf_iterator<char> Parser::EndOfFile = std::istreambuf_iterator<char>();

////////////////////////////////////////////////////////////////////////////////////////////////////

Parser::Parser(std::istream &istream)
:	m_istream(istream),
	m_position(m_istream),
	m_row{1},
	m_column{1},
	m_endOfFile{false}
{
	std::setlocale(LC_NUMERIC, "C");

	// Don’t skip whitespace
	istream.exceptions(std::istream::badbit);

	checkStream();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

size_t Parser::row() const
{
	return m_row;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

size_t Parser::column() const
{
	return m_column;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

char Parser::currentCharacter() const
{
	checkStream();

	return *m_position;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

bool Parser::atEndOfFile() const
{
	return m_position.equal(EndOfFile);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void Parser::checkStream() const
{
	if (atEndOfFile())
		throw ParserException(m_row, m_column, "Reading past end of file");

	if (m_istream.fail())
		throw ParserException(m_row, m_column);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void Parser::advance()
{
	checkStream();

	const auto character = currentCharacter();

	if (character == '\n')
	{
		m_row++;
		m_column = 1;
	}
	else if (std::isblank(character) || std::isprint(character))
		m_column++;

	m_position++;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

bool Parser::advanceIf(char expectedCharacter)
{
	checkStream();

	if (currentCharacter() != expectedCharacter)
		return false;

	advance();

	return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void Parser::skipWhiteSpace()
{
	return skipWhiteSpace(
		[](const auto character)
		{
			return std::isspace(character);
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void Parser::skipLine()
{
	checkStream();

	while (currentCharacter() != '\n')
		advance();

	advance();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

std::string Parser::getLine()
{
	checkStream();

	std::string value;

	while (true)
	{
		const auto character = currentCharacter();

		advance();

		if (character == '\n')
			break;
		else if (character == '\r')
			continue;

		value.push_back(character);
	}

	return value;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
std::string Parser::parse<std::string>()
{
	skipWhiteSpace();

	std::string value;

	while (true)
	{
		const auto character = currentCharacter();

		if (std::isspace(character))
			break;

		value.push_back(character);
		advance();
	}

	return value;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<std::string>(const std::string &expectedValue)
{
	BOOST_ASSERT(!std::isspace(expectedValue[0]));

	skipWhiteSpace();

	std::for_each(expectedValue.cbegin(), expectedValue.cend(),
		[&](const auto &expectedCharacter)
		{
			const auto character = static_cast<char>(this->currentCharacter());

			if (character != expectedCharacter)
				throw ParserException(m_row, m_column, "Unexpected string, expected \"" + expectedValue + "\" (expected character '" + expectedCharacter + "', got '" + character + "')");

			this->advance();
		});
}

////////////////////////////////////////////////////////////////////////////////////////////////////

uint64_t Parser::parseIntegerBody()
{
	checkStream();

	if (!std::isdigit(currentCharacter()))
		throw ParserException(m_row, m_column, "Could not parse integer value");

	uint64_t value = 0;

	while (!atEndOfFile())
	{
		const auto character = currentCharacter();

		if (!std::isdigit(character))
			break;

		value *= 10;
		value += character - '0';

		advance();
	}

	return value;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
int64_t Parser::parse<int64_t>()
{
	skipWhiteSpace();

	bool positive = advanceIf('+') || !advanceIf('-');

	const auto value = parseIntegerBody();

	return (positive ? value : -value);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
uint64_t Parser::parse<uint64_t>()
{
	skipWhiteSpace();

	if (currentCharacter() == '-')
		throw ParserException(m_row, m_column, "Expected unsigned integer, got signed one");

	return parseIntegerBody();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<int64_t>(const int64_t &expectedValue)
{
	const auto value = parse<int64_t>();

	if (value != expectedValue)
		throw ParserException(m_row, m_column, "Unexpected value " + std::to_string(value) + ", expected " + std::to_string(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<uint64_t>(const uint64_t &expectedValue)
{
	const auto value = parse<uint64_t>();

	if (value != expectedValue)
		throw ParserException(m_row, m_column, "Unexpected value " + std::to_string(value) + ", expected " + std::to_string(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
int32_t Parser::parse<int32_t>()
{
	return static_cast<int32_t>(parse<int64_t>());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
uint32_t Parser::parse<uint32_t>()
{
	return static_cast<uint32_t>(parse<uint64_t>());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<int32_t>(const int32_t &expectedValue)
{
	expect<int64_t>(static_cast<int64_t>(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<uint32_t>(const uint32_t &expectedValue)
{
	expect<uint64_t>(static_cast<uint64_t>(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
int16_t Parser::parse<int16_t>()
{
	return static_cast<int16_t>(parse<int64_t>());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
uint16_t Parser::parse<uint16_t>()
{
	return static_cast<uint16_t>(parse<uint64_t>());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<int16_t>(const int16_t &expectedValue)
{
	expect<int64_t>(static_cast<int64_t>(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<uint16_t>(const uint16_t &expectedValue)
{
	expect<uint64_t>(static_cast<uint64_t>(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
int8_t Parser::parse<int8_t>()
{
	return static_cast<int8_t>(parse<int64_t>());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
uint8_t Parser::parse<uint8_t>()
{
	return static_cast<uint8_t>(parse<uint64_t>());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<int8_t>(const int8_t &expectedValue)
{
	expect<int64_t>(static_cast<int64_t>(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<uint8_t>(const uint8_t &expectedValue)
{
	expect<uint64_t>(static_cast<uint64_t>(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
bool Parser::parse<bool>()
{
	skipWhiteSpace();

	if (advanceIf('0'))
	    return false;

	if (advanceIf('1'))
		return true;

	throw ParserException(m_row, m_column, "Could not parse Boolean value");
}

////////////////////////////////////////////////////////////////////////////////////////////////////

template<>
void Parser::expect<bool>(const bool &expectedValue)
{
	const auto value = parse<bool>();

	if (value != expectedValue)
		throw ParserException(m_row, m_column, "Unexpected value " + std::to_string(value) + ", expected " + std::to_string(expectedValue));
}

////////////////////////////////////////////////////////////////////////////////////////////////////

}
}
<|endoftext|>


<commit_before>/* Copyright (c) 2013-2014 Jeffrey Pfau
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GBAApp.h"

#include "AudioProcessor.h"
#include "Display.h"
#include "GameController.h"
#include "Window.h"
#include "VFileDevice.h"

#include <QFileInfo>
#include <QFileOpenEvent>
#include <QIcon>
#include <QTranslator>

extern "C" {
#include "core/version.h"
#include "feature/commandline.h"
#include "util/nointro.h"
#include "util/socket.h"
}

using namespace QGBA;

static GBAApp* g_app = nullptr;

mLOG_DEFINE_CATEGORY(QT, "Qt");

GBAApp::GBAApp(int& argc, char* argv[])
	: QApplication(argc, argv)
	, m_windows{}
	, m_db(nullptr)
{
	g_app = this;

#ifdef BUILD_SDL
	SDL_Init(SDL_INIT_NOPARACHUTE);
#endif

#ifndef Q_OS_MAC
	setWindowIcon(QIcon(":/res/mgba-1024.png"));
#endif

	QTranslator* translator = new QTranslator(this);
	if (translator->load(QLocale("es"), QLatin1String(binaryName), QLatin1String("-"), QLatin1String(":/translations"))) {
		installTranslator(translator);
	}

	SocketSubsystemInit();
	qRegisterMetaType<const uint32_t*>("const uint32_t*");
	qRegisterMetaType<mCoreThread*>("mCoreThread*");

	QApplication::setApplicationName(projectName);
	QApplication::setApplicationVersion(projectVersion);

	if (!m_configController.getQtOption("displayDriver").isNull()) {
		Display::setDriver(static_cast<Display::Driver>(m_configController.getQtOption("displayDriver").toInt()));
	}

	mArguments args;
	mGraphicsOpts graphicsOpts;
	mSubParser subparser;
	initParserForGraphics(&subparser, &graphicsOpts);
	bool loaded = m_configController.parseArguments(&args, argc, argv, &subparser);
	if (loaded && args.showHelp) {
		usage(argv[0], subparser.usage);
		::exit(0);
		return;
	}

	reloadGameDB();

	if (!m_configController.getQtOption("audioDriver").isNull()) {
		AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController.getQtOption("audioDriver").toInt()));
	}
	Window* w = new Window(&m_configController);
	connect(w, &Window::destroyed, [this]() {
		m_windows[0] = nullptr;
	});
	m_windows[0] = w;

	if (loaded) {
		w->argumentsPassed(&args);
	} else {
		w->loadConfig();
	}
	freeArguments(&args);

	if (graphicsOpts.multiplier) {
		w->resizeFrame(QSize(VIDEO_HORIZONTAL_PIXELS * graphicsOpts.multiplier, VIDEO_VERTICAL_PIXELS * graphicsOpts.multiplier));
	}
	if (graphicsOpts.fullscreen) {
		w->enterFullScreen();
	}

	w->show();

	w->controller()->setMultiplayerController(&m_multiplayer);
	w->multiplayerChanged();
}

bool GBAApp::event(QEvent* event) {
	if (event->type() == QEvent::FileOpen) {
		m_windows[0]->controller()->loadGame(static_cast<QFileOpenEvent*>(event)->file());
		return true;
	}
	return QApplication::event(event);
}

Window* GBAApp::newWindow() {
	if (m_multiplayer.attached() >= MAX_GBAS) {
		return nullptr;
	}
	Window* w = new Window(&m_configController, m_multiplayer.attached());
	int windowId = m_multiplayer.attached();
	connect(w, &Window::destroyed, [this, windowId]() {
		m_windows[windowId] = nullptr;
	});
	m_windows[windowId] = w;
	w->setAttribute(Qt::WA_DeleteOnClose);
	w->loadConfig();
	w->show();
	w->controller()->setMultiplayerController(&m_multiplayer);
	w->multiplayerChanged();
	return w;
}

GBAApp* GBAApp::app() {
	return g_app;
}

void GBAApp::pauseAll(QList<int>* paused) {
	for (int i = 0; i < MAX_GBAS; ++i) {
		if (!m_windows[i] || !m_windows[i]->controller()->isLoaded() || m_windows[i]->controller()->isPaused()) {
			continue;
		}
		m_windows[i]->controller()->setPaused(true);
		paused->append(i);
	}
}

void GBAApp::continueAll(const QList<int>* paused) {
	for (int i : *paused) {
		m_windows[i]->controller()->setPaused(false);
	}
}

QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QString& filter) {
	QList<int> paused;
	pauseAll(&paused);
	QString filename = QFileDialog::getOpenFileName(owner, title, m_configController.getQtOption("lastDirectory").toString(), filter);
	continueAll(&paused);
	if (!filename.isEmpty()) {
		m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
	}
	return filename;
}

QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QString& filter) {
	QList<int> paused;
	pauseAll(&paused);
	QString filename = QFileDialog::getSaveFileName(owner, title, m_configController.getQtOption("lastDirectory").toString(), filter);
	continueAll(&paused);
	if (!filename.isEmpty()) {
		m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
	}
	return filename;
}

QString GBAApp::getOpenDirectoryName(QWidget* owner, const QString& title) {
	QList<int> paused;
	pauseAll(&paused);
	QString filename = QFileDialog::getExistingDirectory(owner, title, m_configController.getQtOption("lastDirectory").toString());
	continueAll(&paused);
	if (!filename.isEmpty()) {
		m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
	}
	return filename;
}

QFileDialog* GBAApp::getOpenFileDialog(QWidget* owner, const QString& title, const QString& filter) {
	FileDialog* dialog = new FileDialog(this, owner, title, filter);
	dialog->setAcceptMode(QFileDialog::AcceptOpen);
	return dialog;
}

QFileDialog* GBAApp::getSaveFileDialog(QWidget* owner, const QString& title, const QString& filter) {
	FileDialog* dialog = new FileDialog(this, owner, title, filter);
	dialog->setAcceptMode(QFileDialog::AcceptSave);
	return dialog;
}

QString GBAApp::dataDir() {
#ifdef DATADIR
	QString path = QString::fromUtf8(DATADIR);
#else
	QString path = QCoreApplication::applicationDirPath();
#ifdef Q_OS_MAC
	path += QLatin1String("/../Resources");
#endif
#endif
	return path;
}

bool GBAApp::reloadGameDB() {
	NoIntroDB* db = nullptr;
	VFile* vf = VFileDevice::open(dataDir() + "/nointro.dat", O_RDONLY);
	if (vf) {
		db = NoIntroDBLoad(vf);
		vf->close(vf);
	}
	if (db && m_db) {
		NoIntroDBDestroy(m_db);
	}
	if (db) {
		m_db = db;
		return true;
	}
	return false;
}

GBAApp::FileDialog::FileDialog(GBAApp* app, QWidget* parent, const QString& caption, const QString& filter)
	: QFileDialog(parent, caption, app->m_configController.getQtOption("lastDirectory").toString(), filter)
	, m_app(app)
{
}

int GBAApp::FileDialog::exec() {
	QList<int> paused;
	m_app->pauseAll(&paused);
	bool didAccept = QFileDialog::exec() == QDialog::Accepted;
	QStringList filenames = selectedFiles();
	if (!filenames.isEmpty()) {
		m_app->m_configController.setQtOption("lastDirectory", QFileInfo(filenames[0]).dir().path());
	}
	m_app->continueAll(&paused);
	return didAccept;
}
<commit_msg>Qt: Remove testing code<commit_after>/* Copyright (c) 2013-2014 Jeffrey Pfau
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GBAApp.h"

#include "AudioProcessor.h"
#include "Display.h"
#include "GameController.h"
#include "Window.h"
#include "VFileDevice.h"

#include <QFileInfo>
#include <QFileOpenEvent>
#include <QIcon>
#include <QTranslator>

extern "C" {
#include "core/version.h"
#include "feature/commandline.h"
#include "util/nointro.h"
#include "util/socket.h"
}

using namespace QGBA;

static GBAApp* g_app = nullptr;

mLOG_DEFINE_CATEGORY(QT, "Qt");

GBAApp::GBAApp(int& argc, char* argv[])
	: QApplication(argc, argv)
	, m_windows{}
	, m_db(nullptr)
{
	g_app = this;

#ifdef BUILD_SDL
	SDL_Init(SDL_INIT_NOPARACHUTE);
#endif

#ifndef Q_OS_MAC
	setWindowIcon(QIcon(":/res/mgba-1024.png"));
#endif

	QTranslator* translator = new QTranslator(this);
	if (translator->load(QLocale(), QLatin1String(binaryName), QLatin1String("-"), QLatin1String(":/translations"))) {
		installTranslator(translator);
	}

	SocketSubsystemInit();
	qRegisterMetaType<const uint32_t*>("const uint32_t*");
	qRegisterMetaType<mCoreThread*>("mCoreThread*");

	QApplication::setApplicationName(projectName);
	QApplication::setApplicationVersion(projectVersion);

	if (!m_configController.getQtOption("displayDriver").isNull()) {
		Display::setDriver(static_cast<Display::Driver>(m_configController.getQtOption("displayDriver").toInt()));
	}

	mArguments args;
	mGraphicsOpts graphicsOpts;
	mSubParser subparser;
	initParserForGraphics(&subparser, &graphicsOpts);
	bool loaded = m_configController.parseArguments(&args, argc, argv, &subparser);
	if (loaded && args.showHelp) {
		usage(argv[0], subparser.usage);
		::exit(0);
		return;
	}

	reloadGameDB();

	if (!m_configController.getQtOption("audioDriver").isNull()) {
		AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController.getQtOption("audioDriver").toInt()));
	}
	Window* w = new Window(&m_configController);
	connect(w, &Window::destroyed, [this]() {
		m_windows[0] = nullptr;
	});
	m_windows[0] = w;

	if (loaded) {
		w->argumentsPassed(&args);
	} else {
		w->loadConfig();
	}
	freeArguments(&args);

	if (graphicsOpts.multiplier) {
		w->resizeFrame(QSize(VIDEO_HORIZONTAL_PIXELS * graphicsOpts.multiplier, VIDEO_VERTICAL_PIXELS * graphicsOpts.multiplier));
	}
	if (graphicsOpts.fullscreen) {
		w->enterFullScreen();
	}

	w->show();

	w->controller()->setMultiplayerController(&m_multiplayer);
	w->multiplayerChanged();
}

bool GBAApp::event(QEvent* event) {
	if (event->type() == QEvent::FileOpen) {
		m_windows[0]->controller()->loadGame(static_cast<QFileOpenEvent*>(event)->file());
		return true;
	}
	return QApplication::event(event);
}

Window* GBAApp::newWindow() {
	if (m_multiplayer.attached() >= MAX_GBAS) {
		return nullptr;
	}
	Window* w = new Window(&m_configController, m_multiplayer.attached());
	int windowId = m_multiplayer.attached();
	connect(w, &Window::destroyed, [this, windowId]() {
		m_windows[windowId] = nullptr;
	});
	m_windows[windowId] = w;
	w->setAttribute(Qt::WA_DeleteOnClose);
	w->loadConfig();
	w->show();
	w->controller()->setMultiplayerController(&m_multiplayer);
	w->multiplayerChanged();
	return w;
}

GBAApp* GBAApp::app() {
	return g_app;
}

void GBAApp::pauseAll(QList<int>* paused) {
	for (int i = 0; i < MAX_GBAS; ++i) {
		if (!m_windows[i] || !m_windows[i]->controller()->isLoaded() || m_windows[i]->controller()->isPaused()) {
			continue;
		}
		m_windows[i]->controller()->setPaused(true);
		paused->append(i);
	}
}

void GBAApp::continueAll(const QList<int>* paused) {
	for (int i : *paused) {
		m_windows[i]->controller()->setPaused(false);
	}
}

QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QString& filter) {
	QList<int> paused;
	pauseAll(&paused);
	QString filename = QFileDialog::getOpenFileName(owner, title, m_configController.getQtOption("lastDirectory").toString(), filter);
	continueAll(&paused);
	if (!filename.isEmpty()) {
		m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
	}
	return filename;
}

QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QString& filter) {
	QList<int> paused;
	pauseAll(&paused);
	QString filename = QFileDialog::getSaveFileName(owner, title, m_configController.getQtOption("lastDirectory").toString(), filter);
	continueAll(&paused);
	if (!filename.isEmpty()) {
		m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
	}
	return filename;
}

QString GBAApp::getOpenDirectoryName(QWidget* owner, const QString& title) {
	QList<int> paused;
	pauseAll(&paused);
	QString filename = QFileDialog::getExistingDirectory(owner, title, m_configController.getQtOption("lastDirectory").toString());
	continueAll(&paused);
	if (!filename.isEmpty()) {
		m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
	}
	return filename;
}

QFileDialog* GBAApp::getOpenFileDialog(QWidget* owner, const QString& title, const QString& filter) {
	FileDialog* dialog = new FileDialog(this, owner, title, filter);
	dialog->setAcceptMode(QFileDialog::AcceptOpen);
	return dialog;
}

QFileDialog* GBAApp::getSaveFileDialog(QWidget* owner, const QString& title, const QString& filter) {
	FileDialog* dialog = new FileDialog(this, owner, title, filter);
	dialog->setAcceptMode(QFileDialog::AcceptSave);
	return dialog;
}

QString GBAApp::dataDir() {
#ifdef DATADIR
	QString path = QString::fromUtf8(DATADIR);
#else
	QString path = QCoreApplication::applicationDirPath();
#ifdef Q_OS_MAC
	path += QLatin1String("/../Resources");
#endif
#endif
	return path;
}

bool GBAApp::reloadGameDB() {
	NoIntroDB* db = nullptr;
	VFile* vf = VFileDevice::open(dataDir() + "/nointro.dat", O_RDONLY);
	if (vf) {
		db = NoIntroDBLoad(vf);
		vf->close(vf);
	}
	if (db && m_db) {
		NoIntroDBDestroy(m_db);
	}
	if (db) {
		m_db = db;
		return true;
	}
	return false;
}

GBAApp::FileDialog::FileDialog(GBAApp* app, QWidget* parent, const QString& caption, const QString& filter)
	: QFileDialog(parent, caption, app->m_configController.getQtOption("lastDirectory").toString(), filter)
	, m_app(app)
{
}

int GBAApp::FileDialog::exec() {
	QList<int> paused;
	m_app->pauseAll(&paused);
	bool didAccept = QFileDialog::exec() == QDialog::Accepted;
	QStringList filenames = selectedFiles();
	if (!filenames.isEmpty()) {
		m_app->m_configController.setQtOption("lastDirectory", QFileInfo(filenames[0]).dir().path());
	}
	m_app->continueAll(&paused);
	return didAccept;
}
<|endoftext|>


<commit_before>#include <fcntl.h>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <vector>

#include "common.hpp"
#include "utils/file.hpp"

using namespace polybar;
using namespace std;

#ifndef IPC_CHANNEL_PREFIX
#define IPC_CHANNEL_PREFIX "/tmp/polybar_mqueue."
#endif

void log(const string& msg) {
  fprintf(stderr, "polybar-msg: %s\n", msg.c_str());
}

void log(int exit_code, const string& msg) {
  fprintf(stderr, "polybar-msg: %s\n", msg.c_str());
  exit(exit_code);
}

void usage(const string& parameters) {
  fprintf(stderr, "Usage: polybar-msg [-p pid] %s\n", parameters.c_str());
  exit(127);
}

bool validate_type(const string& type) {
  if (type == "action") {
    return true;
  } else if (type == "cmd") {
    return true;
  } else if (type == "hook") {
    return true;
  } else {
    return false;
  }
}

int main(int argc, char** argv) {
  const int E_GENERIC{1};
  const int E_NO_CHANNELS{2};
  const int E_MESSAGE_TYPE{3};
  const int E_INVALID_PID{4};
  const int E_INVALID_CHANNEL{5};
  const int E_WRITE{6};

  vector<string> args{argv + 1, argv + argc};
  string::size_type p;
  int pid{0};

  // If -p <pid> is passed, check if the process is running and that
  // a valid channel pipe is available
  if (args.size() >= 2 && args[0].compare(0, 2, "-p") == 0) {
    if (!file_util::exists("/proc/" + args[1])) {
      log(E_INVALID_PID, "No process with pid " + args[1]);
    } else if (!file_util::is_fifo(IPC_CHANNEL_PREFIX + args[1])) {
      log(E_INVALID_CHANNEL, "No channel available for pid " + args[1]);
    }

    pid = atoi(args[1].c_str());
    args.erase(args.begin());
    args.erase(args.begin());
  }

  // Validate args
  if (args.size() < 2) {
    usage("<command=(action|cmd|hook)> <payload> [...]");
  } else if (!validate_type(args[0])) {
    log(E_MESSAGE_TYPE, "\"" + args[0] + "\" is not a valid type.");
  }

  string ipc_type{args[0]};
  args.erase(args.begin());
  string ipc_payload{args[0]};
  args.erase(args.begin());

  // Check hook specific args
  if (ipc_type == "hook") {
    if (args.size() != 1) {
      usage("hook <module-name> <hook-index>");
    } else if ((p = ipc_payload.find("module/")) != 0) {
      ipc_payload = "module/" + ipc_payload + args[0];
      args.erase(args.begin());
    } else {
      ipc_payload += args[0];
      args.erase(args.begin());
    }
  }

  // Get availble channel pipes
  auto channels = file_util::glob(IPC_CHANNEL_PREFIX + "*"s);
  if (channels.empty()) {
    log(E_NO_CHANNELS, "There are no active ipc channels");
  }

  // Write the message to each channel in the list and remove stale
  // channel pipes that may be left lingering if the owning process got
  // SIGKILLED or crashed
  for (auto&& channel : channels) {
    string handle{channel};
    int handle_pid{0};

    if ((p = handle.rfind('.')) != string::npos) {
      handle_pid = atoi(handle.substr(p + 1).c_str());
    }

    if (!file_util::exists("/proc/" + to_string(handle_pid))) {
      if (unlink(handle.c_str()) == -1) {
        log(E_GENERIC, "Could not remove stale ipc channel: "s + strerror(errno));
      } else {
        log("Removed stale ipc channel: " + handle);
      }
    } else if (!pid || pid == handle_pid) {
      string payload{ipc_type + ':' + ipc_payload};
      file_descriptor fd(handle, O_WRONLY);
      if (write(fd, payload.c_str(), payload.size()) != -1) {
        log("Successfully wrote \"" + payload + "\" to \"" + handle + "\"");
      } else {
        log(E_WRITE, "Failed to write \"" + payload + "\" to \"" + handle + "\" (err: " + strerror(errno) + ")");
      }
    }
  }

  return 0;
}
<commit_msg>refactor(ipc): More state checks<commit_after>#include <fcntl.h>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <vector>

#include "common.hpp"
#include "utils/file.hpp"
#include "utils/io.hpp"

using namespace polybar;
using namespace std;

#ifndef IPC_CHANNEL_PREFIX
#define IPC_CHANNEL_PREFIX "/tmp/polybar_mqueue."
#endif

void log(const string& msg) {
  fprintf(stderr, "polybar-msg: %s\n", msg.c_str());
}

void log(int exit_code, const string& msg) {
  fprintf(stderr, "polybar-msg: %s\n", msg.c_str());
  exit(exit_code);
}

void usage(const string& parameters) {
  fprintf(stderr, "Usage: polybar-msg [-p pid] %s\n", parameters.c_str());
  exit(127);
}

void remove_pipe(const string& handle) {
  if (unlink(handle.c_str()) == -1) {
    log(1, "Could not remove stale ipc channel: "s + strerror(errno));
  } else {
    log("Removed stale ipc channel: " + handle);
  }
}

bool validate_type(const string& type) {
  if (type == "action") {
    return true;
  } else if (type == "cmd") {
    return true;
  } else if (type == "hook") {
    return true;
  } else {
    return false;
  }
}

int main(int argc, char** argv) {
  const int E_NO_CHANNELS{2};
  const int E_MESSAGE_TYPE{3};
  const int E_INVALID_PID{4};
  const int E_INVALID_CHANNEL{5};
  const int E_WRITE{6};

  vector<string> args{argv + 1, argv + argc};
  string::size_type p;
  int pid{0};

  // If -p <pid> is passed, check if the process is running and that
  // a valid channel pipe is available
  if (args.size() >= 2 && args[0].compare(0, 2, "-p") == 0) {
    if (!file_util::exists("/proc/" + args[1])) {
      log(E_INVALID_PID, "No process with pid " + args[1]);
    } else if (!file_util::exists(IPC_CHANNEL_PREFIX + args[1])) {
      log(E_INVALID_CHANNEL, "No channel available for pid " + args[1]);
    }

    pid = atoi(args[1].c_str());
    args.erase(args.begin());
    args.erase(args.begin());
  }

  // Validate args
  auto help = find_if(args.begin(), args.end(), [](string a) { return a == "-h" || a == "--help"; }) != args.end();
  if (help || args.size() < 2) {
    usage("<command=(action|cmd|hook)> <payload> [...]");
  } else if (!validate_type(args[0])) {
    log(E_MESSAGE_TYPE, "\"" + args[0] + "\" is not a valid type.");
  }

  string ipc_type{args[0]};
  args.erase(args.begin());
  string ipc_payload{args[0]};
  args.erase(args.begin());

  // Check hook specific args
  if (ipc_type == "hook") {
    if (args.size() != 1) {
      usage("hook <module-name> <hook-index>");
    } else if ((p = ipc_payload.find("module/")) != 0) {
      ipc_payload = "module/" + ipc_payload + args[0];
      args.erase(args.begin());
    } else {
      ipc_payload += args[0];
      args.erase(args.begin());
    }
  }

  // Get availble channel pipes
  auto pipes = file_util::glob(IPC_CHANNEL_PREFIX + "*"s);

  // Remove stale channel files without a running parent process
  for (auto it = pipes.rbegin(); it != pipes.rend(); it++) {
    if ((p = it->rfind('.')) == string::npos) {
      continue;
    } else if (!file_util::exists("/proc/" + it->substr(p + 1))) {
      remove_pipe(*it);
      pipes.erase(remove(pipes.begin(), pipes.end(), *it), pipes.end());
    } else if (pid && to_string(pid) != it->substr(p + 1)) {
      pipes.erase(remove(pipes.begin(), pipes.end(), *it), pipes.end());
    }
  }

  if (pipes.empty()) {
    log(E_NO_CHANNELS, "No active ipc channels");
  }

  int exit_status = 127;

  // Write message to each available channel or match
  // against pid if one was defined
  for (auto&& channel : pipes) {
    try {
      file_descriptor fd(channel, O_WRONLY | O_NONBLOCK);
      string payload{ipc_type + ':' + ipc_payload};
      if (write(fd, payload.c_str(), payload.size()) != -1) {
        log("Successfully wrote \"" + payload + "\" to \"" + channel + "\"");
        exit_status = 0;
      } else {
        log(E_WRITE, "Failed to write \"" + payload + "\" to \"" + channel + "\" (err: " + strerror(errno) + ")");
      }
    } catch (const exception& err) {
      remove_pipe(channel);
    }
  }

  return exit_status;
}
<|endoftext|>