<commit_before>#include "optimize.hpp"

#include <vector>
#include <cmath>
#include <cstdlib>
#include <cassert>
#include <stdexcept>
#include <limits>
#include <algorithm>

#include "pll_util.hpp"
#include "constants.hpp"
#include "Log.hpp"

using namespace std;

static void traverse_update_partials(pll_utree_t * tree, pll_partition_t * partition,
    pll_utree_t ** travbuffer, double * branch_lengths, unsigned int * matrix_indices,
    pll_operation_t * operations)
{
  unsigned int num_matrices, num_ops;
  vector<unsigned int> param_indices(partition->rate_cats, 0);
  /* perform a full traversal*/
  assert(tree->next != nullptr);
  unsigned int traversal_size;
  // TODO this only needs to be done once, outside of this func. pass traversal size also
  // however this is practically nonexistent impact compared to clv comp
  pll_utree_traverse(tree, cb_full_traversal, travbuffer, &traversal_size);

  /* given the computed traversal descriptor, generate the operations
     structure, and the corresponding probability matrix indices that
     may need recomputing */
  pll_utree_create_operations(travbuffer,
                              traversal_size,
                              branch_lengths,
                              matrix_indices,
                              operations,
                              &num_matrices,
                              &num_ops);

  pll_update_prob_matrices(partition,
                           &param_indices[0],
                           matrix_indices,// matrices to update
                           branch_lengths,
                           num_matrices); // how many should be updated

  /* use the operations array to compute all num_ops inner CLVs. Operations
     will be carried out sequentially starting from operation 0 towrds num_ops-1 */
  pll_update_partials(partition, operations, num_ops);

}

double optimize_branch_triplet(pll_partition_t * partition, pll_utree_t * tree)
{
  if (!tree->next)
    tree = tree->back;

  vector<pll_utree_t*> travbuffer(4);
  vector<double> branch_lengths(3);
  vector<unsigned int> matrix_indices(3);
  vector<pll_operation_t> operations(4);

  traverse_update_partials(tree, partition, &travbuffer[0], &branch_lengths[0],
    &matrix_indices[0], &operations[0]);

  vector<unsigned int> param_indices(partition->rate_cats, 0);

  auto cur_logl = -numeric_limits<double>::infinity();
  int smoothings = 32;

  cur_logl = -pllmod_opt_optimize_branch_lengths_local (
                                                  partition,
                                                  tree,
                                                  &param_indices[0],
                                                  PLLMOD_OPT_MIN_BRANCH_LEN,
                                                  PLLMOD_OPT_MAX_BRANCH_LEN,
                                                  OPT_BRANCH_EPSILON,
                                                  smoothings,
                                                  1, // radius
                                                  1); // keep update

  return cur_logl;
}

static double optimize_branch_lengths(pll_utree_t * tree, pll_partition_t * partition, pll_optimize_options_t& params,
  pll_utree_t ** travbuffer, double cur_logl, double lnl_monitor, int* smoothings)
{
  if (!tree->next)
    tree = tree->back;

  traverse_update_partials(tree, partition, travbuffer, params.lk_params.branch_lengths,
    params.lk_params.matrix_indices, params.lk_params.operations);

  pll_errno = 0; // hotfix

  vector<unsigned int> param_indices(partition->rate_cats, 0);

  cur_logl = -1 * pllmod_opt_optimize_branch_lengths_iterative(
    partition,
    tree,
    &param_indices[0],
    PLLMOD_OPT_MIN_BRANCH_LEN,
    PLLMOD_OPT_MAX_BRANCH_LEN,
    OPT_BRANCH_EPSILON,
    *smoothings,
    1); // keep updating BLs during call

  if (cur_logl+1e-6 < lnl_monitor)
    throw runtime_error{string("cur_logl < lnl_monitor: ") + to_string(cur_logl) + string(" : ")
    + to_string(lnl_monitor)};

  // reupdate the indices as they may have changed
  params.lk_params.where.unrooted_t.parent_clv_index = tree->clv_index;
  params.lk_params.where.unrooted_t.parent_scaler_index = tree->scaler_index;
  params.lk_params.where.unrooted_t.child_clv_index = tree->back->clv_index;
  params.lk_params.where.unrooted_t.child_scaler_index = tree->back->scaler_index;
  params.lk_params.where.unrooted_t.edge_pmatrix_index = tree->pmatrix_index;

  traverse_update_partials(tree, partition, travbuffer, params.lk_params.branch_lengths,
    params.lk_params.matrix_indices, params.lk_params.operations);
    cur_logl = pll_compute_edge_loglikelihood (partition, tree->clv_index,
                                                  tree->scaler_index,
                                                  tree->back->clv_index,
                                                  tree->back->scaler_index,
                                                  tree->pmatrix_index, &param_indices[0], nullptr);

  return cur_logl;
}

void optimize(Model& model, pll_utree_t * tree, pll_partition_t * partition,
  const Tree_Numbers& nums, const bool opt_branches, const bool opt_model)
{
  if (!opt_branches && !opt_model)
    return;

  if (opt_branches)
    set_branch_lengths(tree, DEFAULT_BRANCH_LENGTH);

  compute_and_set_empirical_frequencies(partition, model);

  auto symmetries = (&(model.symmetries())[0]);
  vector<unsigned int> param_indices(model.rate_cats(), 0);

  // sadly we explicitly need these buffers here and in the params structure
  vector<pll_utree_t*> travbuffer(nums.nodes);
  vector<double> branch_lengths(nums.branches);
  vector<unsigned int> matrix_indices(nums.branches);
  vector<pll_operation_t> operations(nums.nodes);

  traverse_update_partials(tree, partition, &travbuffer[0], &branch_lengths[0],
    &matrix_indices[0], &operations[0]);

  // compute logl once to give us a logl starting point
  auto cur_logl = pll_compute_edge_loglikelihood (partition, tree->clv_index,
                                                tree->scaler_index,
                                                tree->back->clv_index,
                                                tree->back->scaler_index,
                                                tree->pmatrix_index, &param_indices[0], nullptr);

  // double cur_logl = -numeric_limits<double>::infinity();
  int smoothings;
  double lnl_monitor = cur_logl;

  // set up high level options structure
  pll_optimize_options_t params;
  params.lk_params.partition = partition;
  params.lk_params.operations = &operations[0];
  params.lk_params.branch_lengths = &branch_lengths[0];
  params.lk_params.matrix_indices = &matrix_indices[0];
  params.lk_params.params_indices = &param_indices[0];
  params.lk_params.alpha_value = model.alpha();
  params.lk_params.rooted = 0;
  params.lk_params.where.unrooted_t.parent_clv_index = tree->clv_index;
  params.lk_params.where.unrooted_t.parent_scaler_index = tree->scaler_index;
  params.lk_params.where.unrooted_t.child_clv_index = tree->back->clv_index;
  params.lk_params.where.unrooted_t.child_scaler_index =
    tree->back->scaler_index;
  params.lk_params.where.unrooted_t.edge_pmatrix_index = tree->pmatrix_index;

  /* optimization parameters */
  params.params_index = 0;
  params.subst_params_symmetries = symmetries;
  params.factr = OPT_FACTR;
  params.pgtol = OPT_PARAM_EPSILON;

  vector<pll_utree_t*> branches(nums.branches);
  auto num_traversed = utree_query_branches(tree, &branches[0]);
  assert (num_traversed == nums.branches);
  unsigned int branch_index = 0;

  double logl = cur_logl;

  if (opt_branches)
  {
    smoothings = 8;
    cur_logl = optimize_branch_lengths(branches[branch_index],
      partition, params, &travbuffer[0], cur_logl, lnl_monitor, &smoothings);

    // lgr << "after hidden blo crouching tiger: " << to_string(cur_logl) << "\n";

  }

  #define RATE_MIN     1e-4
  #define RATE_MAX     1000000.
  double min_rates[6] = {RATE_MIN,RATE_MIN,RATE_MIN,RATE_MIN,RATE_MIN,RATE_MIN};
  double max_rates[6] = {RATE_MAX,RATE_MAX,RATE_MAX,RATE_MAX,RATE_MAX,RATE_MAX};

  do
  {
    branch_index = rand () % num_traversed;

    // lgr << "Start: " << to_string(cur_logl) << "\n";
    logl = cur_logl;

    if (opt_model)
    {

      params.which_parameters = PLLMOD_OPT_PARAM_SUBST_RATES;
      cur_logl = -pllmod_opt_optimize_multidim(&params, min_rates, max_rates);

      // lgr << "after rates: " << to_string(cur_logl) << "\n";

      if (opt_branches)
      {
        smoothings = 2;
        cur_logl = optimize_branch_lengths(branches[branch_index],
          partition, params, &travbuffer[0], cur_logl, lnl_monitor, &smoothings);

        // lgr << "after blo 1: " << to_string(cur_logl) << "\n";

      }

      // params.which_parameters = PLL_PARAMETER_FREQUENCIES;
      // pll_optimize_parameters_multidim(&params, nullptr, nullptr);

      if (opt_branches)
      {
        smoothings = 2;
        cur_logl = optimize_branch_lengths(branches[branch_index],
          partition, params, &travbuffer[0], cur_logl, lnl_monitor, &smoothings);

        // lgr << "after blo 2: " << to_string(cur_logl) << "\n";

      }

      // params.which_parameters = PLL_PARAMETER_PINV;
      // cur_logl = -1 * pll_optimize_parameters_brent(&params);
      params.which_parameters = PLLMOD_OPT_PARAM_ALPHA;
      cur_logl = -pllmod_opt_optimize_onedim(&params, 0.02, 10000.);

      // lgr << "after alpha: " << to_string(cur_logl) << "\n";

    }

    if (opt_branches)
    {
      smoothings = 3;
      cur_logl = optimize_branch_lengths(branches[branch_index],
        partition, params, &travbuffer[0], cur_logl, lnl_monitor, &smoothings);

      // lgr << "after blo 3: " << to_string(cur_logl) << "\n";

    }
  } while (fabs (cur_logl - logl) > OPT_EPSILON);

  if (opt_model)
  {
    // update epa model object as well
    model.alpha(params.lk_params.alpha_value);
    model.substitution_rates(partition->subst_params[0], 6);
    model.base_frequencies(partition->frequencies[params.params_index], partition->states);
  }
}

void compute_and_set_empirical_frequencies(pll_partition_t * partition, Model& model)
{
  double * empirical_freqs = pllmod_msa_empirical_frequencies (partition);

  pll_set_frequencies (partition, 0, empirical_freqs);
  model.base_frequencies(partition->frequencies[0], partition->states);
  free (empirical_freqs);
}
<commit_msg>fixed bug during model update of optimization<commit_after>#include "optimize.hpp"

#include <vector>
#include <cmath>
#include <cstdlib>
#include <cassert>
#include <stdexcept>
#include <limits>
#include <algorithm>

#include "pll_util.hpp"
#include "constants.hpp"
#include "Log.hpp"

using namespace std;

static void traverse_update_partials(pll_utree_t * tree, pll_partition_t * partition,
    pll_utree_t ** travbuffer, double * branch_lengths, unsigned int * matrix_indices,
    pll_operation_t * operations)
{
  unsigned int num_matrices, num_ops;
  vector<unsigned int> param_indices(partition->rate_cats, 0);
  /* perform a full traversal*/
  assert(tree->next != nullptr);
  unsigned int traversal_size;
  // TODO this only needs to be done once, outside of this func. pass traversal size also
  // however this is practically nonexistent impact compared to clv comp
  pll_utree_traverse(tree, cb_full_traversal, travbuffer, &traversal_size);

  /* given the computed traversal descriptor, generate the operations
     structure, and the corresponding probability matrix indices that
     may need recomputing */
  pll_utree_create_operations(travbuffer,
                              traversal_size,
                              branch_lengths,
                              matrix_indices,
                              operations,
                              &num_matrices,
                              &num_ops);

  pll_update_prob_matrices(partition,
                           &param_indices[0],
                           matrix_indices,// matrices to update
                           branch_lengths,
                           num_matrices); // how many should be updated

  /* use the operations array to compute all num_ops inner CLVs. Operations
     will be carried out sequentially starting from operation 0 towrds num_ops-1 */
  pll_update_partials(partition, operations, num_ops);

}

double optimize_branch_triplet(pll_partition_t * partition, pll_utree_t * tree)
{
  if (!tree->next)
    tree = tree->back;

  vector<pll_utree_t*> travbuffer(4);
  vector<double> branch_lengths(3);
  vector<unsigned int> matrix_indices(3);
  vector<pll_operation_t> operations(4);

  traverse_update_partials(tree, partition, &travbuffer[0], &branch_lengths[0],
    &matrix_indices[0], &operations[0]);

  vector<unsigned int> param_indices(partition->rate_cats, 0);

  auto cur_logl = -numeric_limits<double>::infinity();
  int smoothings = 32;

  cur_logl = -pllmod_opt_optimize_branch_lengths_local (
                                                  partition,
                                                  tree,
                                                  &param_indices[0],
                                                  PLLMOD_OPT_MIN_BRANCH_LEN,
                                                  PLLMOD_OPT_MAX_BRANCH_LEN,
                                                  OPT_BRANCH_EPSILON,
                                                  smoothings,
                                                  1, // radius
                                                  1); // keep update

  return cur_logl;
}

static double optimize_branch_lengths(pll_utree_t * tree, pll_partition_t * partition, pll_optimize_options_t& params,
  pll_utree_t ** travbuffer, double cur_logl, double lnl_monitor, int* smoothings)
{
  if (!tree->next)
    tree = tree->back;

  traverse_update_partials(tree, partition, travbuffer, params.lk_params.branch_lengths,
    params.lk_params.matrix_indices, params.lk_params.operations);

  pll_errno = 0; // hotfix

  vector<unsigned int> param_indices(partition->rate_cats, 0);

  cur_logl = -1 * pllmod_opt_optimize_branch_lengths_iterative(
    partition,
    tree,
    &param_indices[0],
    PLLMOD_OPT_MIN_BRANCH_LEN,
    PLLMOD_OPT_MAX_BRANCH_LEN,
    OPT_BRANCH_EPSILON,
    *smoothings,
    1); // keep updating BLs during call

  if (cur_logl+1e-6 < lnl_monitor)
    throw runtime_error{string("cur_logl < lnl_monitor: ") + to_string(cur_logl) + string(" : ")
    + to_string(lnl_monitor)};

  // reupdate the indices as they may have changed
  params.lk_params.where.unrooted_t.parent_clv_index = tree->clv_index;
  params.lk_params.where.unrooted_t.parent_scaler_index = tree->scaler_index;
  params.lk_params.where.unrooted_t.child_clv_index = tree->back->clv_index;
  params.lk_params.where.unrooted_t.child_scaler_index = tree->back->scaler_index;
  params.lk_params.where.unrooted_t.edge_pmatrix_index = tree->pmatrix_index;

  traverse_update_partials(tree, partition, travbuffer, params.lk_params.branch_lengths,
    params.lk_params.matrix_indices, params.lk_params.operations);
    cur_logl = pll_compute_edge_loglikelihood (partition, tree->clv_index,
                                                  tree->scaler_index,
                                                  tree->back->clv_index,
                                                  tree->back->scaler_index,
                                                  tree->pmatrix_index, &param_indices[0], nullptr);

  return cur_logl;
}

void optimize(Model& model, pll_utree_t * tree, pll_partition_t * partition,
  const Tree_Numbers& nums, const bool opt_branches, const bool opt_model)
{
  if (!opt_branches && !opt_model)
    return;

  if (opt_branches)
    set_branch_lengths(tree, DEFAULT_BRANCH_LENGTH);

  compute_and_set_empirical_frequencies(partition, model);

  auto symmetries = (&(model.symmetries())[0]);
  vector<unsigned int> param_indices(model.rate_cats(), 0);

  // sadly we explicitly need these buffers here and in the params structure
  vector<pll_utree_t*> travbuffer(nums.nodes);
  vector<double> branch_lengths(nums.branches);
  vector<unsigned int> matrix_indices(nums.branches);
  vector<pll_operation_t> operations(nums.nodes);

  traverse_update_partials(tree, partition, &travbuffer[0], &branch_lengths[0],
    &matrix_indices[0], &operations[0]);

  // compute logl once to give us a logl starting point
  auto cur_logl = pll_compute_edge_loglikelihood (partition, tree->clv_index,
                                                tree->scaler_index,
                                                tree->back->clv_index,
                                                tree->back->scaler_index,
                                                tree->pmatrix_index, &param_indices[0], nullptr);

  // double cur_logl = -numeric_limits<double>::infinity();
  int smoothings;
  double lnl_monitor = cur_logl;

  // set up high level options structure
  pll_optimize_options_t params;
  params.lk_params.partition = partition;
  params.lk_params.operations = &operations[0];
  params.lk_params.branch_lengths = &branch_lengths[0];
  params.lk_params.matrix_indices = &matrix_indices[0];
  params.lk_params.params_indices = &param_indices[0];
  params.lk_params.alpha_value = model.alpha();
  params.lk_params.rooted = 0;
  params.lk_params.where.unrooted_t.parent_clv_index = tree->clv_index;
  params.lk_params.where.unrooted_t.parent_scaler_index = tree->scaler_index;
  params.lk_params.where.unrooted_t.child_clv_index = tree->back->clv_index;
  params.lk_params.where.unrooted_t.child_scaler_index =
    tree->back->scaler_index;
  params.lk_params.where.unrooted_t.edge_pmatrix_index = tree->pmatrix_index;

  /* optimization parameters */
  params.params_index = 0;
  params.subst_params_symmetries = symmetries;
  params.factr = OPT_FACTR;
  params.pgtol = OPT_PARAM_EPSILON;

  vector<pll_utree_t*> branches(nums.branches);
  auto num_traversed = utree_query_branches(tree, &branches[0]);
  assert (num_traversed == nums.branches);
  unsigned int branch_index = 0;

  double logl = cur_logl;

  if (opt_branches)
  {
    smoothings = 8;
    cur_logl = optimize_branch_lengths(branches[branch_index],
      partition, params, &travbuffer[0], cur_logl, lnl_monitor, &smoothings);

    // lgr << "after hidden blo crouching tiger: " << to_string(cur_logl) << "\n";

  }

  #define RATE_MIN     1e-4
  #define RATE_MAX     1000000.
  double min_rates[6] = {RATE_MIN,RATE_MIN,RATE_MIN,RATE_MIN,RATE_MIN,RATE_MIN};
  double max_rates[6] = {RATE_MAX,RATE_MAX,RATE_MAX,RATE_MAX,RATE_MAX,RATE_MAX};

  do
  {
    branch_index = rand () % num_traversed;

    // lgr << "Start: " << to_string(cur_logl) << "\n";
    logl = cur_logl;

    if (opt_model)
    {

      params.which_parameters = PLLMOD_OPT_PARAM_SUBST_RATES;
      cur_logl = -pllmod_opt_optimize_multidim(&params, min_rates, max_rates);

      // lgr << "after rates: " << to_string(cur_logl) << "\n";

      if (opt_branches)
      {
        smoothings = 2;
        cur_logl = optimize_branch_lengths(branches[branch_index],
          partition, params, &travbuffer[0], cur_logl, lnl_monitor, &smoothings);

        // lgr << "after blo 1: " << to_string(cur_logl) << "\n";

      }

      // params.which_parameters = PLL_PARAMETER_FREQUENCIES;
      // pll_optimize_parameters_multidim(&params, nullptr, nullptr);

      if (opt_branches)
      {
        smoothings = 2;
        cur_logl = optimize_branch_lengths(branches[branch_index],
          partition, params, &travbuffer[0], cur_logl, lnl_monitor, &smoothings);

        // lgr << "after blo 2: " << to_string(cur_logl) << "\n";

      }

      // params.which_parameters = PLL_PARAMETER_PINV;
      // cur_logl = -1 * pll_optimize_parameters_brent(&params);
      params.which_parameters = PLLMOD_OPT_PARAM_ALPHA;
      cur_logl = -pllmod_opt_optimize_onedim(&params, 0.02, 10000.);

      // lgr << "after alpha: " << to_string(cur_logl) << "\n";

    }

    if (opt_branches)
    {
      smoothings = 3;
      cur_logl = optimize_branch_lengths(branches[branch_index],
        partition, params, &travbuffer[0], cur_logl, lnl_monitor, &smoothings);

      // lgr << "after blo 3: " << to_string(cur_logl) << "\n";

    }
  } while (fabs (cur_logl - logl) > OPT_EPSILON);

  if (opt_model)
  {
    // update epa model object as well
    model.alpha(params.lk_params.alpha_value);
    model.substitution_rates(partition->subst_params[0], model.substitution_rates().size());
    model.base_frequencies(partition->frequencies[params.params_index], partition->states);
  }
}

void compute_and_set_empirical_frequencies(pll_partition_t * partition, Model& model)
{
  double * empirical_freqs = pllmod_msa_empirical_frequencies (partition);

  pll_set_frequencies (partition, 0, empirical_freqs);
  model.base_frequencies(partition->frequencies[0], partition->states);
  free (empirical_freqs);
}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkCollection.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include <stdlib.h>
#include <math.h>

#include "vtkCollection.h"

// Description:
// Construct with empty list.
vtkCollection::vtkCollection()
{
  this->NumberOfItems = 0;
  this->Top = NULL;
  this->Bottom = NULL;
  this->Current = NULL;
}

vtkCollection::~vtkCollection()
{
  this->RemoveAllItems();
}

// Description:
// protected function to delete an element. Internal use only.
void vtkCollection::DeleteElement(vtkCollectionElement *e)
{
  delete e;
}

// Description:
// Add an object to the list. Does not prevent duplicate entries.
void vtkCollection::AddItem(vtkObject *a)
{
  vtkCollectionElement *elem;

  elem = new vtkCollectionElement;

  if (!this->Top)
    {
    this->Top = elem;
    }
  else
    {
    this->Bottom->Next = elem;
    }
  this->Bottom = elem;

  elem->Item = a;
  elem->Next = NULL;

  this->NumberOfItems++;
}

// Description:
// Remove an object from the list. Removes the first object found, not
// all occurrences. If no object found, list is unaffected.  See warning
// in description of RemoveItem(int).
void vtkCollection::RemoveItem(vtkObject *a)
{
  int i;
  vtkCollectionElement *elem;

  if (!this->Top)
    {
    return;
    }

  elem = this->Top;
  prev = NULL;
  for (i = 0; i < this->NumberOfItems; i++)
    {
    if (elem->Item == a)
      {
      this->RemoveItem(i);
      return;
      }
    else
      {
      prev = elem;
      elem = elem->Next;
      }
    }
}

// Description:
// Remove all objects from the list.
void vtkCollection::RemoveAllItems()
{
  int i;

  for (i = this->NumberOfItems - 1; i >= 0; i--)
    {
    this->RemoveItem(i);
    }
}

// Description:
// Search for an object and return location in list. If location == 0,
// object was not found.
int vtkCollection::IsItemPresent(vtkObject *a)
{
  int i;
  vtkCollectionElement *elem;

  if (!this->Top)
    {
    return 0;
    }

  elem = this->Top;
  for (i = 0; i < this->NumberOfItems; i++)
    {
    if (elem->Item == a)
      {
      return i + 1;
      }
    else
      {
      elem = elem->Next;
      }
    }

  return 0;
}

// Description:
// Return the number of objects in the list.
int vtkCollection::GetNumberOfItems()
{
  return this->NumberOfItems;
}

void vtkCollection::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkObject::PrintSelf(os,indent);

  os << indent << "Number Of Items: " << this->NumberOfItems << "\n";
}

// Description:
// Get the i'th item in the collection. NULL is returned if i is out
// of range
vtkObject *vtkCollection::GetItemAsObject(int i)
{
  vtkCollectionElement *elem=this->Top;

  if (i < 0)
    {
    return NULL;
    }

  while (elem != NULL && i > 0)
    {
    elem = elem->Next;
    i--;
    }

  if ( elem != NULL )
    {
    return elem->Item;
    }
  else
    {
    return NULL;
    }
}

// Description:
// Replace the i'th item in the collection with a
void vtkCollection::ReplaceItem(int i, vtkObject *a)
{
  vtkCollectionElement *elem;

  if( i < 0 || i >= this->NumberOfItems )
    {
    return;
    }

  elem = this->Top;
  for (int j = 0; j < i; j++, elem = elem->Next )
    {}

  // j == i
  elem->Item = a;
}

// Description:
// Remove the i'th item in the list.
// Be careful if using this function during traversal of the list using
// GetNextItemAsObject (or GetNextItem in derived class).  The list WILL
// be shortened if a valid index is given!  If this->Current is equal to the
// element being removed, have it point to then next element in the list.
void vtkCollection::RemoveItem(int i)
{
  vtkCollectionElement *elem,*prev;

  if( i < 0 || i >= this->NumberOfItems )
    {
    return;
    }

  elem = this->Top;
  prev = NULL;
  for (int j = 0; j < i; j++)
    {
    prev = elem;
    elem = elem->Next;
    }

  // j == i
  if (prev)
    {
    prev->Next = elem->Next;
    }
  else
    {
    this->Top = elem->Next;
    }

  if (!elem->Next)
    {
    this->Bottom = prev;
    }

  if ( this->Current == elem )
    {
    this->Current = elem->Next;
    }

  this->DeleteElement(elem);
  this->NumberOfItems--;
}

<commit_msg>fixed compile errors<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkCollection.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include <stdlib.h>
#include <math.h>

#include "vtkCollection.h"

// Description:
// Construct with empty list.
vtkCollection::vtkCollection()
{
  this->NumberOfItems = 0;
  this->Top = NULL;
  this->Bottom = NULL;
  this->Current = NULL;
}

vtkCollection::~vtkCollection()
{
  this->RemoveAllItems();
}

// Description:
// protected function to delete an element. Internal use only.
void vtkCollection::DeleteElement(vtkCollectionElement *e)
{
  delete e;
}

// Description:
// Add an object to the list. Does not prevent duplicate entries.
void vtkCollection::AddItem(vtkObject *a)
{
  vtkCollectionElement *elem;

  elem = new vtkCollectionElement;

  if (!this->Top)
    {
    this->Top = elem;
    }
  else
    {
    this->Bottom->Next = elem;
    }
  this->Bottom = elem;

  elem->Item = a;
  elem->Next = NULL;

  this->NumberOfItems++;
}

// Description:
// Remove an object from the list. Removes the first object found, not
// all occurrences. If no object found, list is unaffected.  See warning
// in description of RemoveItem(int).
void vtkCollection::RemoveItem(vtkObject *a)
{
  int i;
  vtkCollectionElement *elem;

  if (!this->Top)
    {
    return;
    }

  elem = this->Top;
  for (i = 0; i < this->NumberOfItems; i++)
    {
    if (elem->Item == a)
      {
      this->RemoveItem(i);
      return;
      }
    else
      {
      elem = elem->Next;
      }
    }
}

// Description:
// Remove all objects from the list.
void vtkCollection::RemoveAllItems()
{
  int i;

  for (i = this->NumberOfItems - 1; i >= 0; i--)
    {
    this->RemoveItem(i);
    }
}

// Description:
// Search for an object and return location in list. If location == 0,
// object was not found.
int vtkCollection::IsItemPresent(vtkObject *a)
{
  int i;
  vtkCollectionElement *elem;

  if (!this->Top)
    {
    return 0;
    }

  elem = this->Top;
  for (i = 0; i < this->NumberOfItems; i++)
    {
    if (elem->Item == a)
      {
      return i + 1;
      }
    else
      {
      elem = elem->Next;
      }
    }

  return 0;
}

// Description:
// Return the number of objects in the list.
int vtkCollection::GetNumberOfItems()
{
  return this->NumberOfItems;
}

void vtkCollection::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkObject::PrintSelf(os,indent);

  os << indent << "Number Of Items: " << this->NumberOfItems << "\n";
}

// Description:
// Get the i'th item in the collection. NULL is returned if i is out
// of range
vtkObject *vtkCollection::GetItemAsObject(int i)
{
  vtkCollectionElement *elem=this->Top;

  if (i < 0)
    {
    return NULL;
    }

  while (elem != NULL && i > 0)
    {
    elem = elem->Next;
    i--;
    }

  if ( elem != NULL )
    {
    return elem->Item;
    }
  else
    {
    return NULL;
    }
}

// Description:
// Replace the i'th item in the collection with a
void vtkCollection::ReplaceItem(int i, vtkObject *a)
{
  vtkCollectionElement *elem;

  if( i < 0 || i >= this->NumberOfItems )
    {
    return;
    }

  elem = this->Top;
  for (int j = 0; j < i; j++, elem = elem->Next )
    {}

  // j == i
  elem->Item = a;
}

// Description:
// Remove the i'th item in the list.
// Be careful if using this function during traversal of the list using
// GetNextItemAsObject (or GetNextItem in derived class).  The list WILL
// be shortened if a valid index is given!  If this->Current is equal to the
// element being removed, have it point to then next element in the list.
void vtkCollection::RemoveItem(int i)
{
  vtkCollectionElement *elem,*prev;

  if( i < 0 || i >= this->NumberOfItems )
    {
    return;
    }

  elem = this->Top;
  prev = NULL;
  for (int j = 0; j < i; j++)
    {
    prev = elem;
    elem = elem->Next;
    }

  // j == i
  if (prev)
    {
    prev->Next = elem->Next;
    }
  else
    {
    this->Top = elem->Next;
    }

  if (!elem->Next)
    {
    this->Bottom = prev;
    }

  if ( this->Current == elem )
    {
    this->Current = elem->Next;
    }

  this->DeleteElement(elem);
  this->NumberOfItems--;
}

<|endoftext|>


<commit_before>// Copyright (c) 2013, Matthew Harvey. All rights reserved.

#include "exception.hpp"
#include "array_utilities.hpp"
#include "assert.hpp"
#include "log.hpp"
#include <boost/static_assert.hpp>
#include <cstring>
#include <iostream>
#include <string>

using jewel::num_elements;
using std::endl;
using std::strlen;
using std::strncat;
using std::strncpy;
using std::string;

namespace jewel
{

Exception::Exception() throw()
{
}

Exception::Exception(char const* p_message) throw():
	m_message(p_message)
{
	if (m_message.size() > max_message_size()) truncate_message();
}

Exception::Exception(Exception const& rhs) throw():
	m_message(rhs.m_message)
{
	if (m_message.size() > max_message_size()) truncate_message();
}

Exception::~Exception() throw()
{
}

CappedString<Exception::truncation_flag_capacity>
Exception::truncation_flag()
{
	CappedString<truncation_flag_capacity> const ret("[TRUNCATED]");
	JEWEL_ASSERT (!ret.is_truncated());
	JEWEL_ASSERT (ret.size() == truncation_flag_capacity);
	return ret;
}

char const* Exception::what() const throw()
{
	return m_message.c_str();
}

void
Exception::truncate_message()
{
	// TODO This concatenation would be better handled within
	// CappedString.
	char buf[message_capacity + 1];
	size_t const truncation_flag_size = truncation_flag().size();
	size_t const truncated_message_size =
		message_capacity - truncation_flag_size;
	strncpy(buf, m_message.c_str(), truncated_message_size);
	buf[truncated_message_size] = '\0';
	JEWEL_ASSERT
	(	truncation_flag_size <=
		(message_capacity - truncated_message_size)
	);
	strcat(buf, truncation_flag().c_str());
	buf[message_capacity] = 1;  // Doesn't matter as long as it's not '\0';
	// We still want m_message to be marked as truncated!
	m_message = CappedString<message_capacity>(buf);
	return;
}

size_t Exception::max_message_size() throw()
{
	return message_capacity - truncation_flag_capacity;
}

}  // namespace jewel
<commit_msg>Used CappedString iterators and std::copy algorithm to simplify implementation of jewel::Exception.<commit_after>// Copyright (c) 2013, Matthew Harvey. All rights reserved.

#include "exception.hpp"
#include "array_utilities.hpp"
#include "assert.hpp"
#include "log.hpp"
#include <boost/static_assert.hpp>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <string>

using jewel::num_elements;
using std::copy;
using std::endl;

namespace jewel
{

Exception::Exception() throw()
{
}

Exception::Exception(char const* p_message) throw():
	m_message(p_message)
{
	if (m_message.size() > max_message_size()) truncate_message();
}

Exception::Exception(Exception const& rhs) throw():
	m_message(rhs.m_message)
{
	if (m_message.size() > max_message_size()) truncate_message();
}

Exception::~Exception() throw()
{
}

CappedString<Exception::truncation_flag_capacity>
Exception::truncation_flag()
{
	CappedString<truncation_flag_capacity> const ret("[TRUNCATED]");
	JEWEL_ASSERT (!ret.is_truncated());
	JEWEL_ASSERT (ret.size() == truncation_flag_capacity);
	return ret;
}

char const* Exception::what() const throw()
{
	return m_message.c_str();
}

void
Exception::truncate_message()
{
	CappedString<truncation_flag_capacity> const trunc_flag =
		truncation_flag();
	CappedString<message_capacity>::iterator out_it = copy
	(	trunc_flag.begin(),
		trunc_flag.end(),
		m_message.begin() + (message_capacity - trunc_flag.size())
	);
	*out_it = '\0';
	return;
}

size_t Exception::max_message_size() throw()
{
	return message_capacity - truncation_flag_capacity;
}

}  // namespace jewel
<|endoftext|>


<commit_before>#include "XmlHelper.h"
#include "Exceptions.h"
#include "Helper.h"
#include <QXmlSchemaValidator>
#include <QXmlSchema>
#include <QUrl>
#include <QTemporaryFile>
#include <QXmlSimpleReader>
#include <QXmlInputSource>

QString XmlHelper::isValidXml(QString xml_file)
{
	QXmlSimpleReader xmlReader;

	XmlValidationMessageHandler2 handler;
	xmlReader.setContentHandler(&handler);
	xmlReader.setErrorHandler(&handler);

	QFile file(xml_file);
	QXmlInputSource source(&file);

	if (!xmlReader.parse(&source))
	{
		return handler.errorString();
	}
	return "";
}

QString XmlHelper::isValidXml(QString xml_name, QString schema_name)
{
	//create schema url (both for native files and files from resources)
	QUrl schema_url;
	QScopedPointer<QTemporaryFile> tmp_file(QTemporaryFile::createNativeFile(schema_name));
	if (tmp_file!=0)
	{
		schema_url = QUrl::fromLocalFile(tmp_file->fileName());
	}
	else
	{
		schema_url = QUrl::fromLocalFile(schema_name);
	}

	//load schema
	QXmlSchema schema;
	if (!schema.load(schema_url))
	{
		THROW(FileParseException, "XML schema '" + schema_url.toString() + "'  is not valid/present.");
	}

	//validate file
	QXmlSchemaValidator validator(schema);
	XmlValidationMessageHandler handler;
	validator.setMessageHandler(&handler);
	QScopedPointer<QFile> xml_file(Helper::openFileForReading(xml_name));
	if (validator.validate(xml_file.data(), schema_url))
	{
		return "";
	}

	return handler.messages();
}

QString XmlHelper::XmlValidationMessageHandler::messages()
{
	return messages_;
}

void XmlHelper::XmlValidationMessageHandler::handleMessage(QtMsgType /*type*/, const QString& description, const QUrl& /*identifier*/, const QSourceLocation& /*sourceLocation*/)
{
	messages_ = messages_ + description + " ";
}
<commit_msg>Refactoring of text file helper functions.<commit_after>#include "XmlHelper.h"
#include "Exceptions.h"
#include "Helper.h"
#include <QXmlSchemaValidator>
#include <QXmlSchema>
#include <QUrl>
#include <QTemporaryFile>
#include <QXmlSimpleReader>
#include <QXmlInputSource>

QString XmlHelper::isValidXml(QString xml_file)
{
	QXmlSimpleReader xmlReader;

	XmlValidationMessageHandler2 handler;
	xmlReader.setContentHandler(&handler);
	xmlReader.setErrorHandler(&handler);

	QFile file(xml_file);
	QXmlInputSource source(&file);

	if (!xmlReader.parse(&source))
	{
		return handler.errorString();
	}
	return "";
}

QString XmlHelper::isValidXml(QString xml_name, QString schema_name)
{
	//create schema url (both for native files and files from resources)
	QUrl schema_url;
	QScopedPointer<QTemporaryFile> tmp_file(QTemporaryFile::createNativeFile(schema_name));
	if (tmp_file!=0)
	{
		schema_url = QUrl::fromLocalFile(tmp_file->fileName());
	}
	else
	{
		schema_url = QUrl::fromLocalFile(schema_name);
	}

	//load schema
	QXmlSchema schema;
	if (!schema.load(schema_url))
	{
		THROW(FileParseException, "XML schema '" + schema_url.toString() + "'  is not valid/present.");
	}

	//validate file
	QXmlSchemaValidator validator(schema);
	XmlValidationMessageHandler handler;
	validator.setMessageHandler(&handler);
	QSharedPointer<QFile> xml_file = Helper::openFileForReading(xml_name);
	if (validator.validate(xml_file.data(), schema_url))
	{
		return "";
	}

	return handler.messages();
}

QString XmlHelper::XmlValidationMessageHandler::messages()
{
	return messages_;
}

void XmlHelper::XmlValidationMessageHandler::handleMessage(QtMsgType /*type*/, const QString& description, const QUrl& /*identifier*/, const QSourceLocation& /*sourceLocation*/)
{
	messages_ = messages_ + description + " ";
}
<|endoftext|>


<commit_before>//
//  HTTPServer.cpp
//  Development
//
//  Created by Dmitry Soldatenkov on 12.08.14.
//
//

#include "HTTPServer.h"

#include "net/HttpServer.h"
#include "common/RhodesApp.h"
#include "common/RhoFilePath.h"
#include "common/RhoConf.h"
#include "net/URI.h"
#include "ruby/ext/rho/rhoruby.h"
#include "common/Tokenizer.h"
#include "sync/RhoconnectClientManager.h"
#include "statistic/RhoProfiler.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>

#if !defined(OS_WINCE)
#ifdef OS_ANDROID
#include "../../platform/android/jni/ifaddrs.h"
#else
#include <ifaddrs.h>
#endif
#include <netinet/in.h>
#else
//#include <ws2tcpip.h>
#include "net/CompatWince.h"
#endif

#include <string.h>

#if !defined(WINDOWS_PLATFORM)
#include <arpa/inet.h>
#endif

#include "logging/RhoLog.h"

#define DEFAULT_LOGCATEGORY "Development_HTTPServer"

static DevHTTPServer* ourDevHTTPServer = NULL;

//ULONG GetSinIP(struct sockaddr_in *_psin, LPSTR pIPStr, UINT IPMaxLen)
//{
//    unsigned long ipaddr;
//
//    ipaddr = INADDR_NONE;
//
//    if (pIPStr && IPMaxLen)
//        *pIPStr = '\0';
//
//    if ( _psin )
//    {
//#if defined(_WIN32)
//        ipaddr = _psin->sin_addr.S_un.S_addr;
//#else
//        ipaddr = _psin->sin_addr.s_addr;
//#endif
//
//        if (pIPStr && IPMaxLen)
//        {
//            char  *pIP;
//            struct in_addr in;
//
//#if defined(_WIN32)
//            in.S_un.S_addr = ipaddr;
//#else
//            in.s_addr = ipaddr;
//#endif
//
//            pIP = inet_ntoa(in);
//
//            if (pIP)
//                adjust_str(pIP, pIPStr, IPMaxLen);
//        }
//    }
//
//    return ipaddr;
//}

extern "C" rho::String get_local_ip_adress();

void DevHTTPServer::init() {

    m_local_IP_adress = "";
    rho::String szRootPath = rho_native_rhopath();
    rho::String szUserPath = rho_native_rhouserpath();

    m_httpServer = new rho::net::CHttpServer(RHO_DEVELOPMENT_SERVER_PORT, szRootPath, szUserPath, szRootPath, true, true);

    m_httpServer->disableAllLogging();

#ifdef OS_ANDROID
    m_local_IP_adress = get_local_ip_adress();
#elif defined(OS_WINCE)

    char host[22];
    hostent* host_info = 0 ;

    if(gethostname(host, sizeof(host)) == SOCKET_ERROR) {
        return;
    }

    host_info = gethostbyname(host);

    if(host_info)
    {
        for( int i=0 ; host_info->h_addr_list[i] ; ++i )
        {
            const in_addr* address = (in_addr*)host_info->h_addr_list[i] ;

            rho::String addrIP = inet_ntoa( *address );

            //if (addrIP.find("192.168.") != rho::String::npos) //HOTFIX!!!!
            {
                m_local_IP_adress = addrIP;
                break;
            }
        }
    }
    else
    {
        //error
    }
#else
    //Obtain the computer's IP
    {
        struct ifaddrs * ifAddrStruct=NULL;
        struct ifaddrs * ifa=NULL;
        void * tmpAddrPtr=NULL;

        getifaddrs(&ifAddrStruct);

        for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next)
        {
            if (ifa ->ifa_addr->sa_family == AF_INET) { // check it is IP4
                // is a valid IP4 Address
                tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
                char addressBuffer[INET_ADDRSTRLEN];
                unsigned char *n = (unsigned char*)(tmpAddrPtr);

                inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
                if ((ifa->ifa_name[0] == 'e') && (ifa->ifa_name[1] == 'n')) {
                    //    printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
                    m_local_IP_adress = addressBuffer;
                }
            }
            //   else if (ifa->ifa_addr->sa_family==AF_INET6) { // check it is IP6
            //   // is a valid IP6 Address
            //   tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
            //   char addressBuffer[INET6_ADDRSTRLEN];
            //   inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
            //   printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
            //   }
        }

        if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
    }
#endif

    RAWTRACE("$$$ Our IP adress is : $$$");
    RAWTRACE(m_local_IP_adress.c_str());
    RAWTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$");
}

rho::net::CHttpServer* DevHTTPServer::getHTTPServer() {
    return m_httpServer;
}

DevHTTPServer* DevHTTPServer::getInstance() {
    if (ourDevHTTPServer == NULL) {
        ourDevHTTPServer = new DevHTTPServer();
    }
    return ourDevHTTPServer;
}

rho::String DevHTTPServer::getLocalIPAdress() {
    return m_local_IP_adress;
}

rho::String DevHTTPServer::getPort() {
    rho::String res = "";
    char ttt[16];
    int port = m_httpServer->getPort();
    sprintf(ttt, "%d", port);
    res = ttt;
    return res;
}

void DevHTTPServer::run() {
    for (;;) {
        m_httpServer->run();
    }
}

void init_Development_HTTP_Server() {
    DevHTTPServer * ds = DevHTTPServer::getInstance();
    ds->init();
    ds->start(rho::common::IRhoRunnable::epNormal);
}<commit_msg>[WM] live update: detect local ip<commit_after>//
//  HTTPServer.cpp
//  Development
//
//  Created by Dmitry Soldatenkov on 12.08.14.
//
//

#include "HTTPServer.h"

#include "net/HttpServer.h"
#include "common/RhodesApp.h"
#include "common/RhoFilePath.h"
#include "common/RhoConf.h"
#include "net/URI.h"
#include "ruby/ext/rho/rhoruby.h"
#include "common/Tokenizer.h"
#include "sync/RhoconnectClientManager.h"
#include "statistic/RhoProfiler.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>

#if !defined(OS_WINCE)
#ifdef OS_ANDROID
#include "../../platform/android/jni/ifaddrs.h"
#else
#include <ifaddrs.h>
#endif
#include <netinet/in.h>
#else
//#include <ws2tcpip.h>
#include "net/CompatWince.h"
#endif

#include <string.h>

#if !defined(WINDOWS_PLATFORM)
#include <arpa/inet.h>
#endif

#include "logging/RhoLog.h"

#define DEFAULT_LOGCATEGORY "Development_HTTPServer"

static DevHTTPServer* ourDevHTTPServer = NULL;

//ULONG GetSinIP(struct sockaddr_in *_psin, LPSTR pIPStr, UINT IPMaxLen)
//{
//    unsigned long ipaddr;
//
//    ipaddr = INADDR_NONE;
//
//    if (pIPStr && IPMaxLen)
//        *pIPStr = '\0';
//
//    if ( _psin )
//    {
//#if defined(_WIN32)
//        ipaddr = _psin->sin_addr.S_un.S_addr;
//#else
//        ipaddr = _psin->sin_addr.s_addr;
//#endif
//
//        if (pIPStr && IPMaxLen)
//        {
//            char  *pIP;
//            struct in_addr in;
//
//#if defined(_WIN32)
//            in.S_un.S_addr = ipaddr;
//#else
//            in.s_addr = ipaddr;
//#endif
//
//            pIP = inet_ntoa(in);
//
//            if (pIP)
//                adjust_str(pIP, pIPStr, IPMaxLen);
//        }
//    }
//
//    return ipaddr;
//}

extern "C" rho::String get_local_ip_adress();

void DevHTTPServer::init() {

    m_local_IP_adress = "";
    rho::String szRootPath = rho_native_rhopath();
    rho::String szUserPath = rho_native_rhouserpath();

    m_httpServer = new rho::net::CHttpServer(RHO_DEVELOPMENT_SERVER_PORT, szRootPath, szUserPath, szRootPath, true, true);

    m_httpServer->disableAllLogging();

#ifdef OS_ANDROID
    m_local_IP_adress = get_local_ip_adress();
#elif defined(OS_WINCE)

    char host[22];
    hostent* host_info = 0 ;

    if(gethostname(host, sizeof(host)) == SOCKET_ERROR) {
        return;
    }

    host_info = gethostbyname(host);

    if(host_info)
    {
        const in_addr* address = (in_addr*)host_info->h_addr_list[0];

        rho::String addrIP = inet_ntoa( *address );

        m_local_IP_adress = addrIP;
    }
    else
    {
        //error
    }
#else
    //Obtain the computer's IP
    {
        struct ifaddrs * ifAddrStruct=NULL;
        struct ifaddrs * ifa=NULL;
        void * tmpAddrPtr=NULL;

        getifaddrs(&ifAddrStruct);

        for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next)
        {
            if (ifa ->ifa_addr->sa_family == AF_INET) { // check it is IP4
                // is a valid IP4 Address
                tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
                char addressBuffer[INET_ADDRSTRLEN];
                unsigned char *n = (unsigned char*)(tmpAddrPtr);

                inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
                if ((ifa->ifa_name[0] == 'e') && (ifa->ifa_name[1] == 'n')) {
                    //    printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
                    m_local_IP_adress = addressBuffer;
                }
            }
            //   else if (ifa->ifa_addr->sa_family==AF_INET6) { // check it is IP6
            //   // is a valid IP6 Address
            //   tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
            //   char addressBuffer[INET6_ADDRSTRLEN];
            //   inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
            //   printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
            //   }
        }

        if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
    }
#endif

    RAWTRACE("$$$ Our IP adress is : $$$");
    RAWTRACE(m_local_IP_adress.c_str());
    RAWTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$");
}

rho::net::CHttpServer* DevHTTPServer::getHTTPServer() {
    return m_httpServer;
}

DevHTTPServer* DevHTTPServer::getInstance() {
    if (ourDevHTTPServer == NULL) {
        ourDevHTTPServer = new DevHTTPServer();
    }
    return ourDevHTTPServer;
}

rho::String DevHTTPServer::getLocalIPAdress() {
    return m_local_IP_adress;
}

rho::String DevHTTPServer::getPort() {
    rho::String res = "";
    char ttt[16];
    int port = m_httpServer->getPort();
    sprintf(ttt, "%d", port);
    res = ttt;
    return res;
}

void DevHTTPServer::run() {
    for (;;) {
        m_httpServer->run();
    }
}

void init_Development_HTTP_Server() {
    DevHTTPServer * ds = DevHTTPServer::getInstance();
    ds->init();
    ds->start(rho::common::IRhoRunnable::epNormal);
}<|endoftext|>


<commit_before>#include <iostream>
#include <cstring>
#include <csignal>
#include <list>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include "service.h"
#include "ev++.h"
#include "control.h"

/* TODO: prevent services from respawning too quickly */
/* TODO: detect/guard against dependency cycles */
/* TODO: optional automatic restart of services */

/*
 * "simpleinit" from util-linux package handles signals as follows:
 * SIGTSTP - spawn no more gettys (in preparation for shutdown etc).
 *          In dinit terms this should probably mean "no more auto restarts"
 *          (for any service). (Actually the signal acts as a toggle, if
 *          respawn is disabled it will be re-enabled and init will
 *          act as if SIGHUP had also been sent)
 * SIGTERM - kill spawned gettys (which are still alive)
 *          Interestingly, simpleinit just sends a SIGTERM to the gettys.
 *          "shutdown" however has already sent SIGTERM to every process...
 * "/sbin/initctl -r" - rollback services (ran by "shutdown"/halt etc)
 *           shouldn't return until all services have been stopped.
 *           shutdown calls this *after* sending SIGTERM to all processes.
 *           I guess this allows user processes, if any are still around,
 *           to die before (or just as) the services fall out from underneath
 *           them. On the other hand it largely subverts the ordered service
 *           shutdown that init provides.
 * SIGQUIT - init will exec() shutdown. shutdown will detect that it is
 *           running as pid 1 and will just loop and reap child processes.
 *           This is used by shutdown so that init will not hang on to its
 *           inode, allowing clean filesystem unmounting.
 *
 * Not sent by shutdown:
 * SIGHUP -  re-read inittab and spawn any new getty entries
 * SIGINT - (ctrl+alt+del handler) - fork & exec "reboot"
 *
 * On the contrary dinit currently uses:
 * SIGTERM - roll back services and then exec /sbin/halt
 * SIGINT - roll back services and then exec /sbin/reboot
 *
 * It's an open question about whether dinit should roll back services *before*
 * running halt/reboot, since those commands should prompt rollback of services
 * anyway. But it seems safe to do so.
 */

static bool got_sigterm = false;

static ServiceSet *service_set;

static bool am_system_init = false; // true if we are the system init process
static bool reboot = false; // whether to reboot (instead of halting)

static void sigint_reboot_cb(struct ev_loop *loop, ev_signal *w, int revents);
static void sigquit_cb(struct ev_loop *loop, ev_signal *w, int revents);
static void sigterm_cb(struct ev_loop *loop, ev_signal *w, int revents);

static void open_control_socket(struct ev_loop *loop);

struct ev_io control_socket_io;

int main(int argc, char **argv)
{
    using namespace std;

    am_system_init = (getpid() == 1);

    if (am_system_init) {
        // setup STDIN, STDOUT, STDERR so that we can use them
        int onefd = open("/dev/console", O_RDONLY, 0);
        dup2(onefd, 0);
        int twofd = open("/dev/console", O_RDWR, 0);
        dup2(twofd, 1);
        dup2(twofd, 2);
    }

    /* Set up signal handlers etc */
    /* SIG_CHILD is ignored by default: good */
    /* sigemptyset(&sigwait_set); */
    /* sigaddset(&sigwait_set, SIGCHLD); */
    /* sigaddset(&sigwait_set, SIGINT); */
    /* sigaddset(&sigwait_set, SIGTERM); */
    /* sigprocmask(SIG_BLOCK, &sigwait_set, NULL); */

    /* list of services to start */
    list<const char *> services_to_start;

    /* service directory name */
    const char * service_dir = "/etc/dinit.d";

    /* arguments, if given, specify a list of services to start. */
    /* if none are given the "boot" service is started. */
    if (argc > 1) {
      for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-') {
            // An option...
            if (strcmp(argv[i], "--services-dir") == 0 ||
                    strcmp(argv[i], "-d") == 0) {
                ++i;
                if (i < argc) {
                    service_dir = argv[i];
                }
                else {
                    // error TODO
                }
            }
            else if (strcmp(argv[i], "--help") == 0) {
                cout << "dinit, an init with dependency management" << endl;
                cout << " --help                         : display help" << endl;
                cout << " --services-dir <dir>, -d <dir> : set base directory for service description files (-d <dir>)" << endl;
                cout << " <service-name>                 : start service with name <service-name>" << endl;
                return 0;
            }
            else {
                // unrecognized
                if (! am_system_init) {
                    cerr << "Unrecognized option: " << argv[i] << endl;
                    return 1;
                }
            }
        }
        else {
            // LILO puts "auto" on the kernel command line for unattended boots; we'll filter it.
            if (! am_system_init || strcmp(argv[i], "auto") != 0) {
                services_to_start.push_back(argv[i]);
            }
        }
      }
    }

    if (services_to_start.empty()) {
        services_to_start.push_back("boot");
    }

    // Set up signal handlers
    ev_signal sigint_ev_signal;
    if (am_system_init) {
      ev_signal_init(&sigint_ev_signal, sigint_reboot_cb, SIGINT);
    }
    else {
      ev_signal_init(&sigint_ev_signal, sigterm_cb, SIGINT);
    }

    ev_signal sigquit_ev_signal;
    if (am_system_init) {
        // PID 1: SIGQUIT exec's shutdown
        ev_signal_init(&sigquit_ev_signal, sigquit_cb, SIGQUIT);
    }
    else {
        // Otherwise: SIGQUIT terminates dinit
        ev_signal_init(&sigquit_ev_signal, sigterm_cb, SIGQUIT);
    }

    ev_signal sigterm_ev_signal;
    ev_signal_init(&sigterm_ev_signal, sigterm_cb, SIGTERM);

    /* Set up libev */
    struct ev_loop *loop = ev_default_loop(EVFLAG_AUTO /* | EVFLAG_SIGNALFD */);
    ev_signal_start(loop, &sigint_ev_signal);
    ev_signal_start(loop, &sigquit_ev_signal);
    ev_signal_start(loop, &sigterm_ev_signal);

    // Try to open control socket (may fail due to readonly filesystem)
    open_control_socket(loop);

    /* start requested services */
    service_set = new ServiceSet(service_dir);
    for (list<const char *>::iterator i = services_to_start.begin();
            i != services_to_start.end();
            ++i) {
        try {
            service_set->startService(*i);
        }
        catch (ServiceNotFound &snf) {
            // TODO log this better
            cerr << "Could not find service description: " << snf.serviceName << endl;
        }
        catch (ServiceLoadExc &sle) {
            // TODO log this better
            cerr << "Problem loading service description: " << sle.serviceName << endl;
        }
    }

    event_loop:

    // Process events until all services have terminated.
    while (! service_set->count_active_services() == 0) {
        ev_loop(loop, EVLOOP_ONESHOT);
    }

    if (am_system_init) {
        // TODO log this output properly
        cout << "dinit: No more active services.";
        if (reboot) {
            cout << " Will reboot.";
        }
        else if (got_sigterm) {
            cout << " Will halt.";
        }
        else {
            cout << " Re-initiating boot sequence.";
        }
        cout << endl;
    }

    if (am_system_init) {
        if (reboot) {
            // TODO log error from fork
            if (fork() == 0) {
                execl("/sbin/reboot", "/sbin/reboot", (char *) 0);
            }
        }
        else if (got_sigterm) {
            // TODO log error from fork
            if (fork() == 0) {
                execl("/sbin/halt", "/sbin/halt", (char *) 0);
            }
        }
        else {
            // Hmmmmmm.
            // It could be that we started in single user mode, and the
            // user has now exited the shell. We'll try and re-start the
            // boot process...
            try {
                service_set->startService("boot");
                goto event_loop; // yes, the "evil" goto
            }
            catch (...) {
                // TODO catch exceptions and log message as appropriate
                // Now WTF do we do? try and reboot
                if (fork() == 0) {
                    execl("/sbin/reboot", "/sbin/reboot", (char *) 0);
                }
            }
        }

        // PID 1 should never exit:
        while (true) {
            pause();
        }
    }

    return 0;
}

// Callback for control socket
static void control_socket_cb(struct ev_loop *loop, ev_io *w, int revents)
{
    // Accept a connection
    int sockfd = w->fd;

    int newfd = accept4(sockfd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);

    if (newfd != -1) {
        new ControlConn(loop, service_set, newfd);  // will delete itself when it's finished
        // TODO keep a set of control connections so that we can close them when
        // terminating?
    }
}

static void open_control_socket(struct ev_loop *loop)
{
    // TODO make this use a per-user address if PID != 1, and make the address
    // overridable from the command line

    const char * saddrname = "/dev/dinitctl";
    struct sockaddr_un name;

    unlink(saddrname);

    name.sun_family = AF_UNIX;
    strcpy(name.sun_path, saddrname); // TODO make this safe for long names
    int namelen = 2 + strlen(saddrname);
    //int namelen = sizeof(name);

    int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
    if (sockfd == -1) {
        // TODO log error
        perror("socket");
        return;
    }

    if (bind(sockfd, (struct sockaddr *) &name, namelen) == -1) {
        // TODO log error
        perror("bind");
        close(sockfd);
        return;
    }

    if (listen(sockfd, 10) == -1) {
        // TODO log error
        perror("listen");
        close(sockfd);
        return;
    }

    ev_io_init(&control_socket_io, control_socket_cb, sockfd, EV_READ);
    ev_io_start(loop, &control_socket_io);
}

/* handle SIGINT signal (generated by kernel when ctrl+alt+del pressed) */
static void sigint_reboot_cb(struct ev_loop *loop, ev_signal *w, int revents)
{
    reboot = true;
    service_set->stop_all_services();
}

/* handle SIGQUIT (if we are system init) */
static void sigquit_cb(struct ev_loop *loop, ev_signal *w, int revents)
{
    // This allows remounting the filesystem read-only if the dinit binary has been
    // unlinked. In that case the kernel holds the binary open, so that it can't be
    // properly removed.
    execl("/sbin/shutdown", "/sbin/shutdown", (char *) 0);
}

/* handle SIGTERM - stop all services */
static void sigterm_cb(struct ev_loop *loop, ev_signal *w, int revents)
{
    got_sigterm = true;
    service_set->stop_all_services();
}
<commit_msg>Just adding some comments.<commit_after>#include <iostream>
#include <cstring>
#include <csignal>
#include <list>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include "service.h"
#include "ev++.h"
#include "control.h"

/* TODO: prevent services from respawning too quickly */
/* TODO: detect/guard against dependency cycles */
/* TODO: optional automatic restart of services */

/*
 * "simpleinit" from util-linux package handles signals as follows:
 * SIGTSTP - spawn no more gettys (in preparation for shutdown etc).
 *          In dinit terms this should probably mean "no more auto restarts"
 *          (for any service). (Actually the signal acts as a toggle, if
 *          respawn is disabled it will be re-enabled and init will
 *          act as if SIGHUP had also been sent)
 * SIGTERM - kill spawned gettys (which are still alive)
 *          Interestingly, simpleinit just sends a SIGTERM to the gettys.
 *          "shutdown" however has already sent SIGTERM to every process...
 * "/sbin/initctl -r" - rollback services (ran by "shutdown"/halt etc)
 *           shouldn't return until all services have been stopped.
 *           shutdown calls this *after* sending SIGTERM to all processes.
 *           I guess this allows user processes, if any are still around,
 *           to die before (or just as) the services fall out from underneath
 *           them. On the other hand it largely subverts the ordered service
 *           shutdown that init provides.
 * SIGQUIT - init will exec() shutdown. shutdown will detect that it is
 *           running as pid 1 and will just loop and reap child processes.
 *           This is used by shutdown so that init will not hang on to its
 *           inode, allowing clean filesystem unmounting.
 *
 * Not sent by shutdown:
 * SIGHUP -  re-read inittab and spawn any new getty entries
 * SIGINT - (ctrl+alt+del handler) - fork & exec "reboot"
 *
 * On the contrary dinit currently uses:
 * SIGTERM - roll back services and then exec /sbin/halt
 * SIGINT - roll back services and then exec /sbin/reboot
 *
 * It's an open question about whether dinit should roll back services *before*
 * running halt/reboot, since those commands should prompt rollback of services
 * anyway. But it seems safe to do so.
 */

static bool got_sigterm = false;

static ServiceSet *service_set;

static bool am_system_init = false; // true if we are the system init process
static bool reboot = false; // whether to reboot (instead of halting)

static void sigint_reboot_cb(struct ev_loop *loop, ev_signal *w, int revents);
static void sigquit_cb(struct ev_loop *loop, ev_signal *w, int revents);
static void sigterm_cb(struct ev_loop *loop, ev_signal *w, int revents);

static void open_control_socket(struct ev_loop *loop);

struct ev_io control_socket_io;

int main(int argc, char **argv)
{
    using namespace std;

    am_system_init = (getpid() == 1);

    if (am_system_init) {
        // setup STDIN, STDOUT, STDERR so that we can use them
        int onefd = open("/dev/console", O_RDONLY, 0);
        dup2(onefd, 0);
        int twofd = open("/dev/console", O_RDWR, 0);
        dup2(twofd, 1);
        dup2(twofd, 2);
    }

    /* Set up signal handlers etc */
    /* SIG_CHILD is ignored by default: good */
    /* sigemptyset(&sigwait_set); */
    /* sigaddset(&sigwait_set, SIGCHLD); */
    /* sigaddset(&sigwait_set, SIGINT); */
    /* sigaddset(&sigwait_set, SIGTERM); */
    /* sigprocmask(SIG_BLOCK, &sigwait_set, NULL); */

    /* list of services to start */
    list<const char *> services_to_start;

    /* service directory name */
    const char * service_dir = "/etc/dinit.d";

    // Arguments, if given, specify a list of services to start.
    // If we are running as init (PID=1), the kernel gives us any command line
    // arguments it was given but didn't recognize, including "single" (usual
    // for "boot to single user mode" aka just start the shell). We can treat
    // them as services. In the worst case we can't find any of the named
    // services, and so we'll start the "boot" service by default.
    if (argc > 1) {
      for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-') {
            // An option...
            if (strcmp(argv[i], "--services-dir") == 0 ||
                    strcmp(argv[i], "-d") == 0) {
                ++i;
                if (i < argc) {
                    service_dir = argv[i];
                }
                else {
                    // error TODO
                }
            }
            else if (strcmp(argv[i], "--help") == 0) {
                cout << "dinit, an init with dependency management" << endl;
                cout << " --help                         : display help" << endl;
                cout << " --services-dir <dir>, -d <dir> : set base directory for service description files (-d <dir>)" << endl;
                cout << " <service-name>                 : start service with name <service-name>" << endl;
                return 0;
            }
            else {
                // unrecognized
                if (! am_system_init) {
                    cerr << "Unrecognized option: " << argv[i] << endl;
                    return 1;
                }
            }
        }
        else {
            // LILO puts "auto" on the kernel command line for unattended boots; we'll filter it.
            if (! am_system_init || strcmp(argv[i], "auto") != 0) {
                services_to_start.push_back(argv[i]);
            }
        }
      }
    }

    if (services_to_start.empty()) {
        services_to_start.push_back("boot");
    }

    // Set up signal handlers
    ev_signal sigint_ev_signal;
    if (am_system_init) {
      ev_signal_init(&sigint_ev_signal, sigint_reboot_cb, SIGINT);
    }
    else {
      ev_signal_init(&sigint_ev_signal, sigterm_cb, SIGINT);
    }

    ev_signal sigquit_ev_signal;
    if (am_system_init) {
        // PID 1: SIGQUIT exec's shutdown
        ev_signal_init(&sigquit_ev_signal, sigquit_cb, SIGQUIT);
    }
    else {
        // Otherwise: SIGQUIT terminates dinit
        ev_signal_init(&sigquit_ev_signal, sigterm_cb, SIGQUIT);
    }

    ev_signal sigterm_ev_signal;
    ev_signal_init(&sigterm_ev_signal, sigterm_cb, SIGTERM);

    /* Set up libev */
    struct ev_loop *loop = ev_default_loop(EVFLAG_AUTO /* | EVFLAG_SIGNALFD */);
    ev_signal_start(loop, &sigint_ev_signal);
    ev_signal_start(loop, &sigquit_ev_signal);
    ev_signal_start(loop, &sigterm_ev_signal);

    // Try to open control socket (may fail due to readonly filesystem)
    open_control_socket(loop);

    /* start requested services */
    service_set = new ServiceSet(service_dir);
    for (list<const char *>::iterator i = services_to_start.begin();
            i != services_to_start.end();
            ++i) {
        try {
            service_set->startService(*i);
        }
        catch (ServiceNotFound &snf) {
            // TODO log this better
            cerr << "Could not find service description: " << snf.serviceName << endl;
        }
        catch (ServiceLoadExc &sle) {
            // TODO log this better
            cerr << "Problem loading service description: " << sle.serviceName << endl;
        }
    }

    event_loop:

    // Process events until all services have terminated.
    while (! service_set->count_active_services() == 0) {
        ev_loop(loop, EVLOOP_ONESHOT);
    }

    if (am_system_init) {
        // TODO log this output properly
        cout << "dinit: No more active services.";
        if (reboot) {
            cout << " Will reboot.";
        }
        else if (got_sigterm) {
            cout << " Will halt.";
        }
        else {
            cout << " Re-initiating boot sequence.";
        }
        cout << endl;
    }

    if (am_system_init) {
        if (reboot) {
            // TODO log error from fork
            if (fork() == 0) {
                execl("/sbin/reboot", "/sbin/reboot", (char *) 0);
            }
        }
        else if (got_sigterm) {
            // TODO log error from fork
            if (fork() == 0) {
                execl("/sbin/halt", "/sbin/halt", (char *) 0);
            }
        }
        else {
            // Hmmmmmm.
            // It could be that we started in single user mode, and the
            // user has now exited the shell. We'll try and re-start the
            // boot process...
            try {
                service_set->startService("boot");
                goto event_loop; // yes, the "evil" goto
            }
            catch (...) {
                // TODO catch exceptions and log message as appropriate
                // Now WTF do we do? try and reboot
                if (fork() == 0) {
                    execl("/sbin/reboot", "/sbin/reboot", (char *) 0);
                }
            }
        }

        // PID 1 should never exit:
        while (true) {
            pause();
        }
    }

    return 0;
}

// Callback for control socket
static void control_socket_cb(struct ev_loop *loop, ev_io *w, int revents)
{
    // TODO limit the number of active connections. Keep a tally, and disable the
    // control connection listening socket watcher if it gets high, and re-enable
    // it once it falls below the maximum.

    // Accept a connection
    int sockfd = w->fd;

    int newfd = accept4(sockfd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);

    if (newfd != -1) {
        new ControlConn(loop, service_set, newfd);  // will delete itself when it's finished
        // TODO keep a set of control connections so that we can close them when
        // terminating?
    }
}

static void open_control_socket(struct ev_loop *loop)
{
    // TODO make this use a per-user address if PID != 1, and make the address
    // overridable from the command line

    const char * saddrname = "/dev/dinitctl";
    struct sockaddr_un name;

    unlink(saddrname);

    name.sun_family = AF_UNIX;
    strcpy(name.sun_path, saddrname); // TODO make this safe for long names
    int namelen = 2 + strlen(saddrname);
    //int namelen = sizeof(name);

    int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
    if (sockfd == -1) {
        // TODO log error
        perror("socket");
        return;
    }

    if (bind(sockfd, (struct sockaddr *) &name, namelen) == -1) {
        // TODO log error
        perror("bind");
        close(sockfd);
        return;
    }

    if (listen(sockfd, 10) == -1) {
        // TODO log error
        perror("listen");
        close(sockfd);
        return;
    }

    ev_io_init(&control_socket_io, control_socket_cb, sockfd, EV_READ);
    ev_io_start(loop, &control_socket_io);
}

/* handle SIGINT signal (generated by kernel when ctrl+alt+del pressed) */
static void sigint_reboot_cb(struct ev_loop *loop, ev_signal *w, int revents)
{
    reboot = true;
    service_set->stop_all_services();
}

/* handle SIGQUIT (if we are system init) */
static void sigquit_cb(struct ev_loop *loop, ev_signal *w, int revents)
{
    // This allows remounting the filesystem read-only if the dinit binary has been
    // unlinked. In that case the kernel holds the binary open, so that it can't be
    // properly removed.
    execl("/sbin/shutdown", "/sbin/shutdown", (char *) 0);
}

/* handle SIGTERM - stop all services */
static void sigterm_cb(struct ev_loop *loop, ev_signal *w, int revents)
{
    got_sigterm = true;
    service_set->stop_all_services();
}
<|endoftext|>


<commit_before>#include "Engine.h"
#include "Game.h"
#include "ObjectDummy.h"
#include "BodyRigid.h"
#include "BodyDummy.h"

#include "Physics.h"
#include "ShapeCapsule.h"
#include "ActorBase.h"
#include "Visualizer.h"
#include "sys/SysControl.h"

#ifdef MEMORY_INFO
#define new new(__FILE__, __LINE__)
#endif // MEMORY_INFO

using namespace MathLib;

/*
*/
#define ACTOR_BASE_IFPS             (1.0f / 60.0f)
#define ACTOR_BASE_CLAMP            89.9f
#define ACTOR_BASE_COLLISIONS       4

/*
*/

CActorBase::CActorBase()
{
	m_vUp = vec3(0.0f, 0.0f, 1.0f);
	m_pObject = new CObjectDummy();
	m_pDummy = new CBodyDummy();
	m_pShape = new CShapeCapsule(1.0f, 1.0f);

	m_nFlush = 0;
	m_vPosition = Vec3_zero;
	m_vVelocity = Vec3_zero;
	m_fPhiAngle = 0.0f;			//б		άƽϵУֱYķX֮ļн
	m_fThetaAngle = 0.0f;			//λǣ뵱ǰ˳ʱ߹ĽǶ

	for (int i = 0; i < NUM_STATES; i++)
	{
		m_pStates[i] = 0;
		m_pTimes[i] = 0.0f;
	}

	m_pDummy->SetEnabled(1);
	m_pObject->SetBody(NULL);
	m_pObject->SetBody(m_pDummy);
	m_pShape->SetBody(NULL);
	m_pShape->SetBody(m_pDummy);

	m_pObject->SetWorldTransform(Get_Body_Transform());
	m_pShape->SetRestitution(0.0f);
	m_pShape->SetCollisionMask(2);

	SetEnabled(1);
	SetViewDirection(vec3(0.0f,1.0f,0.0f));
	SetCollision(1);
	SetCollisionRadius(0.3f);
	SetCollisionHeight(1.0f);
	SetFriction(2.0f);
	SetMinVelocity(2.0f);
	SetMaxVelocity(4.0f);
	SetAcceleration(8.0f);
	SetDamping(8.0f);
	SetJumping(1.5f);

	SetGround(0);
	SetCeiling(0);

}
CActorBase::~CActorBase()
{
	m_pDummy->SetObject(NULL);
	delete m_pObject;
	delete m_pDummy;
}

void CActorBase::SetEnabled(int enable)
{
	m_nEnable = enable;
	m_pDummy->SetEnabled(m_nEnable);
}
int CActorBase::IsEnabled() const
{
	return m_nEnable;
}
void CActorBase::Update(float ifps)
{
	if (!m_nEnable)
	{
		return;
	}
	// impulse
	vec3 impulse = vec3_zero;

	// ortho basis
	vec3 tangent, binormal;
	OrthoBasis(m_vUp, tangent, binormal);
}<commit_msg>Signed-off-by: mrlitong <litongtongxue@gmail.com><commit_after>#include "Engine.h"
#include "Game.h"
#include "ObjectDummy.h"
#include "BodyRigid.h"
#include "BodyDummy.h"

#include "Physics.h"
#include "ShapeCapsule.h"
#include "ActorBase.h"
#include "Visualizer.h"
#include "sys/SysControl.h"

#ifdef MEMORY_INFO
#define new new(__FILE__, __LINE__)
#endif // MEMORY_INFO

using namespace MathLib;

/*
*/
#define ACTOR_BASE_IFPS             (1.0f / 60.0f)
#define ACTOR_BASE_CLAMP            89.9f
#define ACTOR_BASE_COLLISIONS       4

/*
*/

CActorBase::CActorBase()
{
	m_vUp = vec3(0.0f, 0.0f, 1.0f);
	m_pObject = new CObjectDummy();
	m_pDummy = new CBodyDummy();
	m_pShape = new CShapeCapsule(1.0f, 1.0f);

	m_nFlush = 0;
	m_vPosition = Vec3_zero;
	m_vVelocity = Vec3_zero;
	m_fPhiAngle = 0.0f;			//б		άƽϵУֱYķX֮ļн
	m_fThetaAngle = 0.0f;			//λǣ뵱ǰ˳ʱ߹ĽǶ

	for (int i = 0; i < NUM_STATES; i++)
	{
		m_pStates[i] = 0;
		m_pTimes[i] = 0.0f;
	}

	m_pDummy->SetEnabled(1);
	m_pObject->SetBody(NULL);
	m_pObject->SetBody(m_pDummy);
	m_pShape->SetBody(NULL);
	m_pShape->SetBody(m_pDummy);

	m_pObject->SetWorldTransform(Get_Body_Transform());
	m_pShape->SetRestitution(0.0f);
	m_pShape->SetCollisionMask(2);

	SetEnabled(1);
	SetViewDirection(vec3(0.0f,1.0f,0.0f));
	SetCollision(1);
	SetCollisionRadius(0.3f);
	SetCollisionHeight(1.0f);
	SetFriction(2.0f);
	SetMinVelocity(2.0f);
	SetMaxVelocity(4.0f);
	SetAcceleration(8.0f);
	SetDamping(8.0f);
	SetJumping(1.5f);

	SetGround(0);
	SetCeiling(0);

}
CActorBase::~CActorBase()
{
	m_pDummy->SetObject(NULL);
	delete m_pObject;
	delete m_pDummy;
}

void CActorBase::SetEnabled(int enable)
{
	m_nEnable = enable;
	m_pDummy->SetEnabled(m_nEnable);
}
int CActorBase::IsEnabled() const
{
	return m_nEnable;
}
void CActorBase::Update(float ifps)
{
	if (!m_nEnable)
	{
		return;
	}
	// impulse
	vec3 impulse = vec3_zero;

	// ortho basis
	vec3 tangent, binormal;
	OrthoBasis(m_vUp, tangent, binormal);
	// current basis
	vec3 x = quat(m_vUp, -m_fPhiAngle) * binormal;
	vec3 y = Normalize(Cross(m_vUp, x));
	vec3 z = Normalize(Cross(x, y));

}<|endoftext|>


<commit_before>/*
 * AdjMatrix.cpp
 *
 *  Created on: 17/apr/2010
 *      Author: ciccio
 */

#include "AdjMatrix.h"
#include <stdio.h>
#include <vector>
#include "globals.h"

using namespace std;

AdjMatrix::AdjMatrix() {
	// TODO Auto-generated constructor stub

}

AdjMatrix::~AdjMatrix() {

	for(int i=0;i<_n;i++)
		delete (*_mat)[i];

	delete *_mat;
	delete _mat;
}

AdjMatrix::AdjMatrix(int n, int m) {
	_n=n;
	_m=m;
	_mat= new int **;
	(*_mat)= new int *[n];

	for(int i=0;i<n;i++)	{
		(*_mat)[i]=new int [m];
		for(int j=0;j<m;j++)
			(*_mat)[i][j]=0;
		}
}

void AdjMatrix::toDot(Nodeset &Ns) {
	FILE *fid;
	Nodeset::iterator i;
	Nodeset::iterator j;
	int ii=0, ij=0;
	fid=fopen((string(protname) + ".dot").c_str(), "w");
	string attr_string="";
	std::map<std::string, std::string>::iterator mapit;
	std::map<std::string, std::string> attribs;

    fprintf(fid, "digraph G {\n");
    fprintf(fid, "node [shape=box, style=rounded];\n");
    fprintf(fid, "rankdir=LR;\n");

    for(i=Ns.begin(); i!=Ns.end(); ++i){
    	attr_string = "[ label = ";
    	attr_string += i->getName();

    	attribs = i->GetAttributes();
    	for(mapit = attribs.begin(); mapit!=attribs.end(); mapit++){
    		attr_string += ", ";
    		attr_string += (mapit -> first).c_str();
			attr_string += " = ";
			attr_string += (mapit -> second).c_str();
    	}
		attr_string += "] ";

    		fprintf(fid, "%d %s;\n", i->getId(), attr_string.c_str());
    		//fprintf(fid, "%d [ label = \"%s\", color = \"%s\" ];\n", i->getId(), i->getName().c_str(), i->GetAttribute("color").c_str());

    }

    for (ii=0;ii<_n;++ii){              // process ARCs
        for (ij=0; ij<_m; ++ij) {
        	if((*_mat)[ii][ij])
                fprintf(fid, "%d->%d;\n", ii, ij);
        }
    }
    fprintf(fid, "}");
    fclose(fid);

}

void AdjMatrix::Set(unsigned i, unsigned j)
{
	(*_mat)[i][j]=1;
}

ostream& AdjMatrix::operator>>(std::ostream &){
	int j,i;

	for(i=0; i<_n; i++){
		for(j=0; j<_m-1; j++)
			cout << (*_mat)[i][j] << ",";
		cout <<(*_mat)[i][j] << endl;
	}
}
<commit_msg>Added empty arrows for F flag.<commit_after>/*
 * AdjMatrix.cpp
 *
 *  Created on: 17/apr/2010
 *      Author: ciccio
 */

#include "AdjMatrix.h"
#include <stdio.h>
#include <vector>
#include "globals.h"

using namespace std;

AdjMatrix::AdjMatrix() {
	// TODO Auto-generated constructor stub

}

AdjMatrix::~AdjMatrix() {

	for(int i=0;i<_n;i++)
		delete (*_mat)[i];

	delete *_mat;
	delete _mat;
}

AdjMatrix::AdjMatrix(int n, int m) {
	_n=n;
	_m=m;
	_mat= new int **;
	(*_mat)= new int *[n];

	for(int i=0;i<n;i++)	{
		(*_mat)[i]=new int [m];
		for(int j=0;j<m;j++)
			(*_mat)[i][j]=0;
		}
}

void AdjMatrix::toDot(Nodeset &Ns) {
	FILE *fid;
	Nodeset::iterator i;
	Nodeset::iterator j;
	int ii=0, ij=0;
	fid=fopen((string(protname) + ".dot").c_str(), "w");
	string attr_string="";
	std::map<std::string, std::string>::iterator mapit;
	std::map<std::string, std::string> attribs;

    fprintf(fid, "digraph G {\n");
    fprintf(fid, "node [shape=box, style=rounded];\n");
    fprintf(fid, "rankdir=LR;\n");

    for(i=Ns.begin(); i!=Ns.end(); ++i){
    	attr_string = "[ label = ";
    	attr_string += i->getName();

    	attribs = i->GetAttributes();
    	for(mapit = attribs.begin(); mapit!=attribs.end(); mapit++){
    		attr_string += ", ";
    		attr_string += (mapit -> first).c_str();
			attr_string += " = ";
			attr_string += (mapit -> second).c_str();
    	}
		attr_string += "] ";

    		fprintf(fid, "%d %s;\n", i->getId(), attr_string.c_str());
    		//fprintf(fid, "%d [ label = \"%s\", color = \"%s\" ];\n", i->getId(), i->getName().c_str(), i->GetAttribute("color").c_str());

    }

    for (ii=0, i=Ns.begin(); ii<_n; ++ii, ++i){              // process ARCs
        for (ij=0; ij<_m; ++ij) {
        	if((*_mat)[ii][ij]) {
        		bool found = false;
        		attribs = i->GetAttributes();
				for(mapit = attribs.begin(); mapit!=attribs.end(); mapit++){
					if(mapit->first == "LEAF_FLAGS" && mapit->second == "F") {
		                fprintf(fid, "%d->%d [arrowhead = \"empty\"];\n", ii, ij);
		                found = true;
					}
				}
				if (!found)
					fprintf(fid, "%d->%d;\n", ii, ij);
        	}
        }
    }
    fprintf(fid, "}");
    fclose(fid);

}

void AdjMatrix::Set(unsigned i, unsigned j)
{
	(*_mat)[i][j]=1;
}

ostream& AdjMatrix::operator>>(std::ostream &){
	int j,i;

	for(i=0; i<_n; i++){
		for(j=0; j<_m-1; j++)
			cout << (*_mat)[i][j] << ",";
		cout <<(*_mat)[i][j] << endl;
	}
}
<|endoftext|>


<commit_before>/*
 *     Copyright 2015 CEA LIST
 *
 *     This file is part of LIMA.
 *
 *     LIMA is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     LIMA is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with LIMA.  If not, see <http://www.gnu.org/licenses/>
 */

#include "LimaFileSystemWatcherTest.h"
#include "common/misc/LimaFileSystemWatcher.h"
#include "common/QsLog/QsLogCategories.h"
#include "common/AbstractFactoryPattern/AmosePluginsManager.h"

#include <QtCore/QTemporaryFile>
#include <QtTest/QtTest>

using namespace Lima;

QTEST_MAIN ( LimaFileSystemWatcherTest );

void LimaFileSystemWatcherTest::initTestCase()
{
    // Called before the first testfunction is executed
  QsLogging::initQsLog();
  // Necessary to initialize factories under Windows
  Lima::AmosePluginsManager::single();
}

void LimaFileSystemWatcherTest::cleanupTestCase()
{
    // Called after the last testfunction was executed
}

void LimaFileSystemWatcherTest::init()
{
    // Called before each testfunction is executed
}

void LimaFileSystemWatcherTest::cleanup()
{
    // Called after every testfunction
}

void LimaFileSystemWatcherTest::LimaFileSystemWatcherTest0()
{
  LimaFileSystemWatcher watcher;

  QSignalSpy stateSpy( &watcher, SIGNAL( fileChanged ( QString) ) );

  QVERIFY( stateSpy.isValid() );

  QCOMPARE( stateSpy.count(), 0 );

  QTemporaryFile tmpFile;
  tmpFile.setAutoRemove(false);
  QVERIFY2(tmpFile.open(),"Was not able to open the temporary file");
  QString tmpFileName = tmpFile.fileName();

  watcher.addPath(tmpFileName);

  QTextStream out(&tmpFile);
  out << "yo";
  tmpFile.close();
  QVERIFY2( QFile(tmpFileName).exists(),  "The tmpFile does not exist while it should");
  QTest::qWait(500);
  // we changed the file. The fileChanged signal should have been triggered
  QCOMPARE( stateSpy.count(), 1 );

  // remove the tmp file. This should trigger the signal
  QFile::remove(tmpFileName);

  QVERIFY2( !QFile(tmpFileName).exists(),  "The tmpFile still exists while it has  been removed");
  QTest::qWait(500);
  // we removed the file. The fileChanged signal should have been triggered
  QCOMPARE( stateSpy.count(), 2 );

  // recreate the file. This should also trigger the signal
  QFile recreatedFile(tmpFileName);
  QVERIFY2( recreatedFile.open(QIODevice::ReadWrite), "Was not able to recreate the file");
  recreatedFile.close();
  QTest::qWait(500);
  // we recreated the file. The fileChanged signal should have been triggered
  QCOMPARE( stateSpy.count(), 3 );

}

<commit_msg>Debug messages<commit_after>/*
 *     Copyright 2015 CEA LIST
 *
 *     This file is part of LIMA.
 *
 *     LIMA is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     LIMA is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with LIMA.  If not, see <http://www.gnu.org/licenses/>
 */

#include "LimaFileSystemWatcherTest.h"
#include "common/misc/LimaFileSystemWatcher.h"
#include "common/QsLog/QsLogCategories.h"
#include "common/AbstractFactoryPattern/AmosePluginsManager.h"

#include <QtCore/QTemporaryFile>
#include <QtTest/QtTest>

using namespace Lima;

QTEST_MAIN ( LimaFileSystemWatcherTest );

void LimaFileSystemWatcherTest::initTestCase()
{
    // Called before the first testfunction is executed
  QsLogging::initQsLog();
  // Necessary to initialize factories under Windows
  Lima::AmosePluginsManager::single();
}

void LimaFileSystemWatcherTest::cleanupTestCase()
{
    // Called after the last testfunction was executed
  std::cerr << "LimaFileSystemWatcherTest::cleanupTestCase" << std::endl;
}

void LimaFileSystemWatcherTest::init()
{
    // Called before each testfunction is executed
}

void LimaFileSystemWatcherTest::cleanup()
{
    // Called after every testfunction
}

void LimaFileSystemWatcherTest::LimaFileSystemWatcherTest0()
{
  LimaFileSystemWatcher watcher;

  QSignalSpy stateSpy( &watcher, SIGNAL( fileChanged ( QString) ) );

  QVERIFY( stateSpy.isValid() );

  QCOMPARE( stateSpy.count(), 0 );

  QTemporaryFile tmpFile;
  QVERIFY2(tmpFile.open(),"Was not able to open the temporary file");
  QString tmpFileName = tmpFile.fileName();

  watcher.addPath(tmpFileName);

  QTextStream out(&tmpFile);
  out << "yo";
  tmpFile.close();
  QVERIFY2( QFile(tmpFileName).exists(),  "The tmpFile does not exist while it should");
  QTest::qWait(500);
  // we changed the file. The fileChanged signal should have been triggered
  QCOMPARE( stateSpy.count(), 1 );
  std::cerr << "LimaFileSystemWatcherTest::LimaFileSystemWatcherTest0 1" << std::endl;

  // remove the tmp file. This should trigger the signal
  QFile::remove(tmpFileName);

  QVERIFY2( !QFile(tmpFileName).exists(),  "The tmpFile still exists while it has  been removed");
  QTest::qWait(500);
  // we removed the file. The fileChanged signal should have been triggered
  QCOMPARE( stateSpy.count(), 2 );
  std::cerr << "LimaFileSystemWatcherTest::LimaFileSystemWatcherTest0 2" << std::endl;

  // recreate the file. This should also trigger the signal
  QFile recreatedFile(tmpFileName);
  QVERIFY2( recreatedFile.open(QIODevice::ReadWrite), "Was not able to recreate the file");
  recreatedFile.close();
  QTest::qWait(500);
  // we recreated the file. The fileChanged signal should have been triggered
  QCOMPARE( stateSpy.count(), 3 );
  std::cerr << "LimaFileSystemWatcherTest::LimaFileSystemWatcherTest0 3" << std::endl;

}

<|endoftext|>