<commit_before>/*
 * IteratorsDemo.cpp
 *
 *  Created on: Nov 4, 2014
 *      Author: Péter Fankhauser
 *	 Institute: ETH Zurich, Autonomous Systems Lab
 */

#include "grid_map_demos/IteratorsDemo.hpp"

// ROS
#include <geometry_msgs/PolygonStamped.h>

using namespace std;
using namespace ros;
using namespace grid_map;

namespace grid_map_demos {

IteratorsDemo::IteratorsDemo(ros::NodeHandle& nodeHandle)
    : nodeHandle_(nodeHandle),
      map_(vector<string>({"type"}))
{
  ROS_INFO("Grid map iterators demo node started.");
  gridMapPublisher_ = nodeHandle_.advertise<grid_map_msgs::GridMap>("grid_map", 1, true);
  polygonPublisher_ = nodeHandle_.advertise<geometry_msgs::PolygonStamped>("polygon", 1, true);

  // Setting up map.
  map_.setGeometry(Length(1.0, 1.0), 0.05, Position(0.0, 0.0));
  map_.setFrameId("map");

  publish();
  ros::Duration duration(2.0);
  duration.sleep();

  demoGridMapIterator();
  demoSubmapIterator();
  demoCircleIterator();
  demoEllipseIterator();
  demoSpiralIterator();
  demoLineIterator();
  demoPolygonIterator();
}

IteratorsDemo::~IteratorsDemo() {}

void IteratorsDemo::demoGridMapIterator()
{
  ROS_INFO("Running grid map iterator demo.");
  map_.clearAll();
  publish();

  for (grid_map::GridMapIterator iterator(map_); !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.01);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::demoSubmapIterator()
{
  ROS_INFO("Running submap iterator demo.");
  map_.clearAll();
  publish();

  Index submapStartIndex(3, 5);
  Index submapBufferSize(12, 7);

  for (grid_map::SubmapIterator iterator(map_, submapStartIndex, submapBufferSize);
      !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.02);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::demoCircleIterator()
{
  ROS_INFO("Running circle iterator demo.");
  map_.clearAll();
  publish();

  Position center(0.0, -0.15);
  double radius = 0.4;

  for (grid_map::CircleIterator iterator(map_, center, radius);
      !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.02);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::demoEllipseIterator()
{
  ROS_INFO("Running ellipse iterator demo.");
  map_.clearAll();
  publish();

  Position center(0.0, -0.15);
  Length length(0.45, 0.9);

  for (grid_map::EllipseIterator iterator(map_, center, length, M_PI_4);
      !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.02);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::demoSpiralIterator()
{
  ROS_INFO("Running spiral iterator demo.");
  map_.clearAll();
  publish();

  Position center(0.0, -0.15);
  double radius = 0.4;

  for (grid_map::SpiralIterator iterator(map_, center, radius);
      !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.02);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::demoLineIterator()
{
  ROS_INFO("Running line iterator demo.");
  map_.clearAll();
  publish();

  Index start(18, 2);
  Index end(2, 13);

  for (grid_map::LineIterator iterator(map_, start, end);
      !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.02);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::demoPolygonIterator()
{
  ROS_INFO("Running polygon iterator demo.");
  map_.clearAll();
  publish();

  grid_map::Polygon polygon;
  polygon.setFrameId(map_.getFrameId());
  polygon.addVertex(Position( 0.480,  0.000));
  polygon.addVertex(Position( 0.164,  0.155));
  polygon.addVertex(Position( 0.116,  0.500));
  polygon.addVertex(Position(-0.133,  0.250));
  polygon.addVertex(Position(-0.480,  0.399));
  polygon.addVertex(Position(-0.316,  0.000));
  polygon.addVertex(Position(-0.480, -0.399));
  polygon.addVertex(Position(-0.133, -0.250));
  polygon.addVertex(Position( 0.116, -0.500));
  polygon.addVertex(Position( 0.164, -0.155));
  polygon.addVertex(Position( 0.480,  0.000));

  geometry_msgs::PolygonStamped message;
  grid_map::PolygonRosConverter::toMessage(polygon, message);
  polygonPublisher_.publish(message);

  for (grid_map::PolygonIterator iterator(map_, polygon);
      !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.02);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::publish()
{
  map_.setTimestamp(ros::Time::now().toNSec());
  grid_map_msgs::GridMap message;
  grid_map::GridMapRosConverter::toMessage(map_, message);
  gridMapPublisher_.publish(message);
  ROS_DEBUG("Grid map (timestamp %f) published.", message.info.header.stamp.toSec());
}

} /* namespace */
<commit_msg>Added comment on iterator performance (#45).<commit_after>/*
 * IteratorsDemo.cpp
 *
 *  Created on: Nov 4, 2014
 *      Author: Péter Fankhauser
 *	 Institute: ETH Zurich, Autonomous Systems Lab
 */

#include "grid_map_demos/IteratorsDemo.hpp"

// ROS
#include <geometry_msgs/PolygonStamped.h>

using namespace std;
using namespace ros;
using namespace grid_map;

namespace grid_map_demos {

IteratorsDemo::IteratorsDemo(ros::NodeHandle& nodeHandle)
    : nodeHandle_(nodeHandle),
      map_(vector<string>({"type"}))
{
  ROS_INFO("Grid map iterators demo node started.");
  gridMapPublisher_ = nodeHandle_.advertise<grid_map_msgs::GridMap>("grid_map", 1, true);
  polygonPublisher_ = nodeHandle_.advertise<geometry_msgs::PolygonStamped>("polygon", 1, true);

  // Setting up map.
  map_.setGeometry(Length(1.0, 1.0), 0.05, Position(0.0, 0.0));
  map_.setFrameId("map");

  publish();
  ros::Duration duration(2.0);
  duration.sleep();

  demoGridMapIterator();
  demoSubmapIterator();
  demoCircleIterator();
  demoEllipseIterator();
  demoSpiralIterator();
  demoLineIterator();
  demoPolygonIterator();
}

IteratorsDemo::~IteratorsDemo() {}

void IteratorsDemo::demoGridMapIterator()
{
  ROS_INFO("Running grid map iterator demo.");
  map_.clearAll();
  publish();

  // Note: In this example we locally store a reference to the map data
  // for improved performance. See `iterator_benchmark.cpp` and the
  // README.md for a comparison and more information.
  grid_map::Matrix& data = map_["type"];
  for (grid_map::GridMapIterator iterator(map_); !iterator.isPastEnd(); ++iterator) {
    const int i = iterator.getLinearIndex();
    data(i) = 1.0;
    publish();
    ros::Duration duration(0.01);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::demoSubmapIterator()
{
  ROS_INFO("Running submap iterator demo.");
  map_.clearAll();
  publish();

  Index submapStartIndex(3, 5);
  Index submapBufferSize(12, 7);

  for (grid_map::SubmapIterator iterator(map_, submapStartIndex, submapBufferSize);
      !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.02);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::demoCircleIterator()
{
  ROS_INFO("Running circle iterator demo.");
  map_.clearAll();
  publish();

  Position center(0.0, -0.15);
  double radius = 0.4;

  for (grid_map::CircleIterator iterator(map_, center, radius);
      !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.02);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::demoEllipseIterator()
{
  ROS_INFO("Running ellipse iterator demo.");
  map_.clearAll();
  publish();

  Position center(0.0, -0.15);
  Length length(0.45, 0.9);

  for (grid_map::EllipseIterator iterator(map_, center, length, M_PI_4);
      !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.02);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::demoSpiralIterator()
{
  ROS_INFO("Running spiral iterator demo.");
  map_.clearAll();
  publish();

  Position center(0.0, -0.15);
  double radius = 0.4;

  for (grid_map::SpiralIterator iterator(map_, center, radius);
      !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.02);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::demoLineIterator()
{
  ROS_INFO("Running line iterator demo.");
  map_.clearAll();
  publish();

  Index start(18, 2);
  Index end(2, 13);

  for (grid_map::LineIterator iterator(map_, start, end);
      !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.02);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::demoPolygonIterator()
{
  ROS_INFO("Running polygon iterator demo.");
  map_.clearAll();
  publish();

  grid_map::Polygon polygon;
  polygon.setFrameId(map_.getFrameId());
  polygon.addVertex(Position( 0.480,  0.000));
  polygon.addVertex(Position( 0.164,  0.155));
  polygon.addVertex(Position( 0.116,  0.500));
  polygon.addVertex(Position(-0.133,  0.250));
  polygon.addVertex(Position(-0.480,  0.399));
  polygon.addVertex(Position(-0.316,  0.000));
  polygon.addVertex(Position(-0.480, -0.399));
  polygon.addVertex(Position(-0.133, -0.250));
  polygon.addVertex(Position( 0.116, -0.500));
  polygon.addVertex(Position( 0.164, -0.155));
  polygon.addVertex(Position( 0.480,  0.000));

  geometry_msgs::PolygonStamped message;
  grid_map::PolygonRosConverter::toMessage(polygon, message);
  polygonPublisher_.publish(message);

  for (grid_map::PolygonIterator iterator(map_, polygon);
      !iterator.isPastEnd(); ++iterator) {
    map_.at("type", *iterator) = 1.0;
    publish();
    ros::Duration duration(0.02);
    duration.sleep();
  }

  ros::Duration duration(1.0);
  duration.sleep();
}

void IteratorsDemo::publish()
{
  map_.setTimestamp(ros::Time::now().toNSec());
  grid_map_msgs::GridMap message;
  grid_map::GridMapRosConverter::toMessage(map_, message);
  gridMapPublisher_.publish(message);
  ROS_DEBUG("Grid map (timestamp %f) published.", message.info.header.stamp.toSec());
}

} /* namespace */
<|endoftext|>


<commit_before>#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real.hpp>
#include <boost/random/variate_generator.hpp>
#include <geometry_msgs/PoseWithCovarianceStamped.h>

class LaserNoise
{
public:
    LaserNoise()
    {
        //randomGen_.seed(time(NULL)); // seed the generator
        laser_sub_ = n_.subscribe<sensor_msgs::LaserScan>("scan", 50, &LaserNoise::laserReadCallBAck, this);
        pose_sub_ = n_.subscribe<geometry_msgs::PoseWithCovarianceStamped>("amcl_pose", 50, &LaserNoise::poseCallback, this);
        scan_pub_ = n_.advertise<sensor_msgs::LaserScan>("scan_with_noise", 50);
        //timerNoise_ = n_.createTimer(ros::Duration(15) , &LaserNoise::timerNoiseCallback, this);
        noiseTriger_ = 0;
    }

private:

    //  boost::mt19937 randomGen_;

    ros::NodeHandle n_;
    ros::Subscriber laser_sub_ , pose_sub_;
    ros::Publisher scan_pub_ ;
    sensor_msgs::LaserScan addedNoiseScan_;

    void laserReadCallBAck(const sensor_msgs::LaserScan::ConstPtr& msg);
    double GaussianKernel(double mu,double sigma), uniformNoise_;
    void poseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg);
    //void timerNoiseCallback(const ros::TimerEvent&);
    //  int point_;
    ros::Timer timerNoise_ ;

    bool noiseTriger_ ; // uniformTriger_;
};

void LaserNoise::laserReadCallBAck(const sensor_msgs::LaserScan::ConstPtr& msg)

{

    double sigma;
    double oldRange;
    addedNoiseScan_ = *msg ;

    //    // random uniform distribution generator for activating noise in random intervals
    //   boost::uniform_real<float> dist2(0,2) ;
    //   double timeInterval = dist2(randomGen_);

    //   // Run the seeding uniform noise code once per timer activation
    //   if (uniformTriger_ == 1)
    //   {
    //    // random uniform distribution generator for unifrom noise
    //    boost::uniform_real<float> distNoise(0,3) ; // noise will be between 0 and 4 meters
    //     uniformNoise_ = distNoise(randomGen_);

    //    // random number generator to add noise in a random reading
    //    boost::uniform_real<float> distPoint(0,(addedNoiseScan_.ranges.size()*0.8)-1 ) ;
    //     point_ = int(distPoinf blabla t(randomGen_));

    //    if (point_ < 0) // safe that the point_ of measurement will be not negative
    //    {
    //        point_ == 0;
    //    }

    //    uniformTriger_ = 0; // reset flag
    //   }

    //    //uniform noise added to a group of reading withint close proximity

    //    if (noiseTriger_ == 1)
    //    {
    //        for (int i= point_; i < (point_ + 30) ; i++)

    //        {
    //            oldRange = addedNoiseScan_.ranges[i] ;
    //            addedNoiseScan_.ranges[i] = addedNoiseScan_.ranges[i] + uniformNoise_;

    //            if (addedNoiseScan_.ranges[i] > addedNoiseScan_.range_max)
    //            { addedNoiseScan_.ranges[i] = addedNoiseScan_.range_max;}

    //            else if (addedNoiseScan_.ranges[i] < addedNoiseScan_.range_min)
    //            { addedNoiseScan_.ranges[i] = addedNoiseScan_.range_min;}
    //        }
    //    }

    // Guassian noise added
    if (noiseTriger_ == 1)
    {
        for (int i=0; i < addedNoiseScan_.ranges.size() ; i++)

        {
            sigma = addedNoiseScan_.ranges[i] * 0.1; // Proportional standard deviation
            oldRange = addedNoiseScan_.ranges[i] ;
            addedNoiseScan_.ranges[i] = addedNoiseScan_.ranges[i] + GaussianKernel(0,sigma);

            if (addedNoiseScan_.ranges[i] > addedNoiseScan_.range_max)
            { addedNoiseScan_.ranges[i] = addedNoiseScan_.range_max;}

            else if (addedNoiseScan_.ranges[i] < addedNoiseScan_.range_min)
            { addedNoiseScan_.ranges[i] = oldRange;}
        }
    }

    addedNoiseScan_.header.stamp = ros::Time::now();

    scan_pub_.publish(addedNoiseScan_);

}

void LaserNoise::poseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg)

{

    if ( (msg->pose.pose.position.x < 18.65) && (msg->pose.pose.position.x > 14.08)
         && (msg->pose.pose.position.y < 19.44) && (msg->pose.pose.position.y > 15.72) )

    {
        noiseTriger_ =1;
    }
    else
        noiseTriger_ = 0;
}

// Noise triger callback
//void LaserNoise::timerNoiseCallback(const ros::TimerEvent&)
//{
//    //uniformTriger_ = 1; // activate uniform noise

//    // alternates between noise and no noise every 1:30 mins
//    if (noiseTriger_ == 0)
//        noiseTriger_ = 1;
//    else
//        noiseTriger_ = 0;

//}

// Utility for adding noise
double LaserNoise::GaussianKernel(double mu,double sigma)
{
    // using Box-Muller transform to generate two independent standard normally disbributed normal variables

    double U = (double)rand()/(double)RAND_MAX; // normalized uniform random variable
    double V = (double)rand()/(double)RAND_MAX; // normalized uniform random variable
    double X = sqrt(-2.0 * ::log(U)) * cos( 2.0*M_PI * V);
    //double Y = sqrt(-2.0 * ::log(U)) * sin( 2.0*M_PI * V); // the other indep. normal variable
    // we'll just use X
    // scale to our mu and sigma
    X = sigma * X + mu;
    return X;
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "laser_noise");
    LaserNoise lasernoise;

    ros::spin();
}
<commit_msg>blabla<commit_after>#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real.hpp>
#include <boost/random/variate_generator.hpp>
#include <geometry_msgs/PoseWithCovarianceStamped.h>

class LaserNoise
{
public:
    LaserNoise()
    {
        //randomGen_.seed(time(NULL)); // seed the generator
        laser_sub_ = n_.subscribe<sensor_msgs::LaserScan>("scan", 50, &LaserNoise::laserReadCallBAck, this);
       // pose_sub_ = n_.subscribe<geometry_msgs::PoseWithCovarianceStamped>("amcl_pose", 50, &LaserNoise::poseCallback, this);
        scan_pub_ = n_.advertise<sensor_msgs::LaserScan>("scan_with_noise", 50);
        timerNoise_ = n_.createTimer(ros::Duration(30) , &LaserNoise::timerNoiseCallback, this);
        noiseTriger_ = 0;
    }

private:

    //  boost::mt19937 randomGen_;

    ros::NodeHandle n_;
    ros::Subscriber laser_sub_ , pose_sub_;
    ros::Publisher scan_pub_ ;
    sensor_msgs::LaserScan addedNoiseScan_;

    void laserReadCallBAck(const sensor_msgs::LaserScan::ConstPtr& msg);
    double GaussianKernel(double mu,double sigma), uniformNoise_;
    //void poseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg);
    void timerNoiseCallback(const ros::TimerEvent&);
    //  int point_;
    ros::Timer timerNoise_ ;

    bool noiseTriger_ ; // uniformTriger_;
};

void LaserNoise::laserReadCallBAck(const sensor_msgs::LaserScan::ConstPtr& msg)

{

    double sigma;
    double oldRange;
    addedNoiseScan_ = *msg ;

    //    // random uniform distribution generator for activating noise in random intervals
    //   boost::uniform_real<float> dist2(0,2) ;
    //   double timeInterval = dist2(randomGen_);

    //   // Run the seeding uniform noise code once per timer activation
    //   if (uniformTriger_ == 1)
    //   {
    //    // random uniform distribution generator for unifrom noise
    //    boost::uniform_real<float> distNoise(0,3) ; // noise will be between 0 and 4 meters
    //     uniformNoise_ = distNoise(randomGen_);

    //    // random number generator to add noise in a random reading
    //    boost::uniform_real<float> distPoint(0,(addedNoiseScan_.ranges.size()*0.8)-1 ) ;
    //     point_ = int(distPoinf blabla t(randomGen_));

    //    if (point_ < 0) // safe that the point_ of measurement will be not negative
    //    {
    //        point_ == 0;
    //    }

    //    uniformTriger_ = 0; // reset flag
    //   }

    //    //uniform noise added to a group of reading withint close proximity

    //    if (noiseTriger_ == 1)
    //    {
    //        for (int i= point_; i < (point_ + 30) ; i++)

    //        {
    //            oldRange = addedNoiseScan_.ranges[i] ;
    //            addedNoiseScan_.ranges[i] = addedNoiseScan_.ranges[i] + uniformNoise_;

    //            if (addedNoiseScan_.ranges[i] > addedNoiseScan_.range_max)
    //            { addedNoiseScan_.ranges[i] = addedNoiseScan_.range_max;}

    //            else if (addedNoiseScan_.ranges[i] < addedNoiseScan_.range_min)
    //            { addedNoiseScan_.ranges[i] = addedNoiseScan_.range_min;}
    //        }
    //    }

    // Guassian noise added
    if (noiseTriger_ == 1)
    {
        for (int i=0; i < addedNoiseScan_.ranges.size() ; i++)

        {
            sigma = addedNoiseScan_.ranges[i] * 0.1; // Proportional standard deviation
            oldRange = addedNoiseScan_.ranges[i] ;
            addedNoiseScan_.ranges[i] = addedNoiseScan_.ranges[i] + GaussianKernel(0,sigma);

            if (addedNoiseScan_.ranges[i] > addedNoiseScan_.range_max)
            { addedNoiseScan_.ranges[i] = addedNoiseScan_.range_max;}

            else if (addedNoiseScan_.ranges[i] < addedNoiseScan_.range_min)
            { addedNoiseScan_.ranges[i] = oldRange;}
        }
    }

    addedNoiseScan_.header.stamp = ros::Time::now();

    scan_pub_.publish(addedNoiseScan_);

}

//void LaserNoise::poseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg)

//{

//    if ( (msg->pose.pose.position.x < 18.65) && (msg->pose.pose.position.x > 14.08)
//         && (msg->pose.pose.position.y < 19.44) && (msg->pose.pose.position.y > 15.72) )

//    {
//        noiseTriger_ =1;
//    }
//    else
//        noiseTriger_ = 0;
//}

// Noise triger callback
void LaserNoise::timerNoiseCallback(const ros::TimerEvent&)
{
    //uniformTriger_ = 1; // activate uniform noise

    // alternates between noise and no noise
    if (noiseTriger_ == 0)
        noiseTriger_ = 1;
    else
        noiseTriger_ = 0;

}

// Utility for adding noise
double LaserNoise::GaussianKernel(double mu,double sigma)
{
    // using Box-Muller transform to generate two independent standard normally disbributed normal variables

    double U = (double)rand()/(double)RAND_MAX; // normalized uniform random variable
    double V = (double)rand()/(double)RAND_MAX; // normalized uniform random variable
    double X = sqrt(-2.0 * ::log(U)) * cos( 2.0*M_PI * V);
    //double Y = sqrt(-2.0 * ::log(U)) * sin( 2.0*M_PI * V); // the other indep. normal variable
    // we'll just use X
    // scale to our mu and sigma
    X = sigma * X + mu;
    return X;
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "laser_noise");
    LaserNoise lasernoise;

    ros::spin();
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include "Time.h"
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <cstdlib>

using namespace std;

int main(int argc, char*argv[])
{
	if(argc < 3){
		cout << "Error: Too few arguements\n";
		return 1;
	}

	string flag;
	if(argc == 4)
	{
		flag = argv[3];
	}

	Timer t;
	double eTime;
	t.start();

	ifstream check(argv[2]);
	if(check)
	{
		cout << "File \"" << argv[2] << "\" already exists.\n";
		return 0;
	}

	ifstream infile(argv[1]);
	ofstream outfile(argv[2]);
	if(!infile.is_open())
	{
		cerr << "File \"" << argv[1] << "\" could not be open\n";
		return 1;
	}
	if(!outfile.is_open())
	{
		cerr << "File \"" << argv[2] << "\" could not be open\n";
		return 1;
	}

	outfile << infile.rdbuf();

	outfile.close();
	infile.close();
	if(flag == "-t")
	{
		t.elapsedWallclockTime(eTime);
		cout << "Wallclock Time: " << eTime << endl;

		t.elapsedUserTime(eTime);
		cout << "User Time: " << eTime << endl;

		t.elapsedSystemTime(eTime);
		cout << "System Time: " << eTime << endl;
	}
	/*----------------------------------------------------------------------*/

	string input = argv[1];
	string output = argv[2];

	int inFile = open(input.c_str(), O_RDONLY);
	int exists = access(output.c_str(), F_OK);
	if(inFile == -1)
	{
		perror("There was an error with open(). ");
		exit(1);
	}
	if(exists == 0)
	{
		cerr << "Error:" <<  output << " already exists.\n";
		return 1;
	}
	int outFile = open(output.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
	if(outFile == -1)
	{
		perror("There was an error with open(). ");
		exit(1);
	}

	char buf[BUFSIZ];
	int n;
	int p;

	while((n = read(inFile, buf, BUFSIZ)) > 0)
	{
		if(n == -1)
		{
			perror("There was an error with read(). ");
			exit(1);
		}
		p = write(outFile, buf, n);
		if(p == -1)
		{
			perror("There was an error with write(). ");
			exit(1);
		}
	}

	return 0;
}
<commit_msg>added my code to cp.cpp<commit_after>#include <iostream>
#include <fstream>
#include "Time.h"
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <cstdlib>

using namespace std;

int main(int argc, char*argv[])
{
	if(argc < 3){
		cout << "Error: Too few arguements\n";
		return 1;
	}

	string flag;
	if(argc == 4)
	{
		flag = argv[3];
	}

	Timer t;
	double eTime;
	t.start();

	ifstream check(argv[2]);
	if(check)
	{
		cout << "File \"" << argv[2] << "\" already exists.\n";
		return 0;
	}

	ifstream infile(argv[1]);
	ofstream outfile(argv[2]);
	if(!infile.is_open())
	{
		cerr << "File \"" << argv[1] << "\" could not be open\n";
		return 1;
	}
	if(!outfile.is_open())
	{
		cerr << "File \"" << argv[2] << "\" could not be open\n";
		return 1;
	}

	outfile << infile.rdbuf();

	outfile.close();
	infile.close();
	if(flag == "-t")
	{
		t.elapsedWallclockTime(eTime);
		cout << "Wallclock Time: " << eTime << endl;

		t.elapsedUserTime(eTime);
		cout << "User Time: " << eTime << endl;

		t.elapsedSystemTime(eTime);
		cout << "System Time: " << eTime << endl;
	}
	/*----------------------------------------------------------------------*/

	string input = argv[1];
	string output = argv[2];

	int inFile = open(input.c_str(), O_RDONLY);
	int exists = access(output.c_str(), F_OK);
	if(inFile == -1)
	{
		perror("There was an error with open(). ");
		exit(1);
	}
	if(exists == 0)
	{
		cerr << "Error:" <<  output << " already exists.\n";
		return 1;
	}
	int outFile = open(output.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
	if(outFile == -1)
	{
		perror("There was an error with open(). ");
		exit(1);
	}

	char buf[BUFSIZ];
	int n;
	int p;

	while((n = read(inFile, buf, BUFSIZ)) > 0)
	{
		if(n == -1)
		{
			perror("There was an error with read(). ");
			exit(1);
		}
		p = write(outFile, buf, n);
		if(p == -1)
		{
			perror("There was an error with write(). ");
			exit(1);
		}
	}

	/***********************************************************************/

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

using namespace std;

int main(int argc, char * argv[]){

        if(argc < 3){
                cout << "** ERROR check inputs arguments ***" << endl;
        }
        else{
                int fdi = open(argv[1],O_RDONLY);
                int fdo = open(argv[2],O_WRONLY | O_CREAT,S_IRWXU);

                if(fdi == -1 || fdo == -1){
                        perror("open");
                }

                void* buf;

                while(int readNum = read(fdi,buf,1) > 0){
                        int writeChk = write(fdo,buf,1);

                        if(readNum == -1){
                                perror("read");
                        }

                        if(writeChk == -1){
                                perror("write");
                        }
                }
        }

        return 0;
}

	return 0;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "Artist.h"
#include "Album.h"
#include "AlbumTrack.h"
#include "Media.h"

#include "database/SqliteTools.h"

const std::string policy::ArtistTable::Name = "artist";
const std::string policy::ArtistTable::CacheColumn = "id_artist";
unsigned int Artist::*const policy::ArtistTable::PrimaryKey = &Artist::m_id;

Artist::Artist( DBConnection dbConnection, sqlite::Row& row )
    : m_dbConnection( dbConnection )
{
    row >> m_id
        >> m_name
        >> m_shortBio
        >> m_artworkUrl
        >> m_nbAlbums;
}

Artist::Artist( const std::string& name )
    : m_id( 0 )
    , m_name( name )
    , m_nbAlbums( 0 )
{
}

unsigned int Artist::id() const
{
    return m_id;
}

const std::string &Artist::name() const
{
    return m_name;
}

const std::string &Artist::shortBio() const
{
    return m_shortBio;
}

bool Artist::setShortBio(const std::string &shortBio)
{
    static const std::string req = "UPDATE " + policy::ArtistTable::Name
            + " SET shortbio = ? WHERE id_artist = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, shortBio, m_id ) == false )
        return false;
    m_shortBio = shortBio;
    return true;
}

std::vector<AlbumPtr> Artist::albums() const
{
    if ( m_id == 0 )
        return {};
    static const std::string req = "SELECT * FROM " + policy::AlbumTable::Name + " alb "
            "WHERE artist_id = ? ORDER BY title";
    return Album::fetchAll( m_dbConnection, req, m_id );
}

std::vector<MediaPtr> Artist::media() const
{
    if ( m_id )
    {
        static const std::string req = "SELECT med.* FROM " + policy::MediaTable::Name + " med "
                "LEFT JOIN MediaArtistRelation mar ON mar.id_media = med.id_media "
                "WHERE mar.id_artist = ?";
        return Media::fetchAll( m_dbConnection, req, m_id );
    }
    else
    {
        // Not being able to rely on ForeignKey here makes me a saaaaad panda...
        // But sqlite only accepts "IS NULL" to compare against NULL...
        static const std::string req = "SELECT med.* FROM " + policy::MediaTable::Name + " med "
                "LEFT JOIN MediaArtistRelation mar ON mar.id_media = med.id_media "
                "WHERE mar.id_artist IS NULL";
        return Media::fetchAll( m_dbConnection, req );
    }
}

bool Artist::addMedia(Media* media)
{
    static const std::string req = "INSERT INTO MediaArtistRelation VALUES(?, ?)";
    // If track's ID is 0, the request will fail due to table constraints
    sqlite::ForeignKey artistForeignKey( m_id );
    return sqlite::Tools::executeRequest( m_dbConnection, req, media->id(), artistForeignKey );
}

const std::string& Artist::artworkUrl() const
{
    return m_artworkUrl;
}

bool Artist::setArtworkUrl( const std::string& artworkUrl )
{
    if ( m_artworkUrl == artworkUrl )
        return true;
    static const std::string req = "UPDATE " + policy::ArtistTable::Name +
            " SET artwork_url = ? WHERE id_artist = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, artworkUrl, m_id ) == false )
        return false;
    m_artworkUrl = artworkUrl;
    return true;
}

bool Artist::updateNbAlbum( int increment )
{
    assert( increment != 0 );
    assert( increment > 0 || ( increment < 0 && m_nbAlbums >= 1 ) );

    static const std::string req = "UPDATE " + policy::ArtistTable::Name +
            " SET nb_albums = nb_albums + ? WHERE id_artist = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, increment, m_id ) == false )
        return false;
    m_nbAlbums += increment;
    return true;
}

std::shared_ptr<Album> Artist::unknownAlbum()
{
    static const std::string req = "SELECT * FROM " + policy::AlbumTable::Name +
                        " WHERE artist_id = ? AND title IS NULL";
    auto album = Album::fetchOne( m_dbConnection, req, m_id );
    if ( album == nullptr )
    {
        album = Album::createUnknownAlbum( m_dbConnection, this );
        if ( album == nullptr )
            return nullptr;
        if ( updateNbAlbum( 1 ) == false )
        {
            Album::destroy( m_dbConnection, album );
            return nullptr;
        }
    }
    return album;
}

bool Artist::createTable( DBConnection dbConnection )
{
    static const std::string req = "CREATE TABLE IF NOT EXISTS " +
            policy::ArtistTable::Name +
            "("
                "id_artist INTEGER PRIMARY KEY AUTOINCREMENT,"
                "name TEXT UNIQUE ON CONFLICT FAIL,"
                "shortbio TEXT,"
                "artwork_url TEXT,"
                "nb_albums UNSIGNED INT DEFAULT 0"
            ")";
    static const std::string reqRel = "CREATE TABLE IF NOT EXISTS MediaArtistRelation("
                "id_media INTEGER NOT NULL,"
                "id_artist INTEGER,"
                "PRIMARY KEY (id_media, id_artist),"
                "FOREIGN KEY(id_media) REFERENCES " + policy::MediaTable::Name +
                "(id_media) ON DELETE CASCADE,"
                "FOREIGN KEY(id_artist) REFERENCES " + policy::ArtistTable::Name + "("
                    + policy::ArtistTable::CacheColumn + ") ON DELETE CASCADE"
            ")";
    return sqlite::Tools::executeRequest( dbConnection, req ) &&
            sqlite::Tools::executeRequest( dbConnection, reqRel );
}

bool Artist::createDefaultArtists( DBConnection dbConnection )
{
    // Don't rely on Artist::create, since we want to insert or do nothing here.
    // This will skip the cache for those new entities, but they will be inserted soon enough anyway.
    static const std::string req = "INSERT OR IGNORE INTO " + policy::ArtistTable::Name +
            "(id_artist) VALUES(?),(?)";
    return sqlite::Tools::executeRequest( dbConnection, req, medialibrary::UnknownArtistID,
                                          medialibrary::VariousArtistID );
}

std::shared_ptr<Artist> Artist::create( DBConnection dbConnection, const std::string &name )
{
    auto artist = std::make_shared<Artist>( name );
    static const std::string req = "INSERT INTO " + policy::ArtistTable::Name +
            "(id_artist, name) VALUES(NULL, ?)";
    if ( _Cache::insert( dbConnection, artist, req, name ) == false )
        return nullptr;
    artist->m_dbConnection = dbConnection;
    return artist;
}

<commit_msg>Artist: Order albums by year & title<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "Artist.h"
#include "Album.h"
#include "AlbumTrack.h"
#include "Media.h"

#include "database/SqliteTools.h"

const std::string policy::ArtistTable::Name = "artist";
const std::string policy::ArtistTable::CacheColumn = "id_artist";
unsigned int Artist::*const policy::ArtistTable::PrimaryKey = &Artist::m_id;

Artist::Artist( DBConnection dbConnection, sqlite::Row& row )
    : m_dbConnection( dbConnection )
{
    row >> m_id
        >> m_name
        >> m_shortBio
        >> m_artworkUrl
        >> m_nbAlbums;
}

Artist::Artist( const std::string& name )
    : m_id( 0 )
    , m_name( name )
    , m_nbAlbums( 0 )
{
}

unsigned int Artist::id() const
{
    return m_id;
}

const std::string &Artist::name() const
{
    return m_name;
}

const std::string &Artist::shortBio() const
{
    return m_shortBio;
}

bool Artist::setShortBio(const std::string &shortBio)
{
    static const std::string req = "UPDATE " + policy::ArtistTable::Name
            + " SET shortbio = ? WHERE id_artist = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, shortBio, m_id ) == false )
        return false;
    m_shortBio = shortBio;
    return true;
}

std::vector<AlbumPtr> Artist::albums() const
{
    if ( m_id == 0 )
        return {};
    static const std::string req = "SELECT * FROM " + policy::AlbumTable::Name + " alb "
            "WHERE artist_id = ? ORDER BY release_year, title";
    return Album::fetchAll( m_dbConnection, req, m_id );
}

std::vector<MediaPtr> Artist::media() const
{
    if ( m_id )
    {
        static const std::string req = "SELECT med.* FROM " + policy::MediaTable::Name + " med "
                "LEFT JOIN MediaArtistRelation mar ON mar.id_media = med.id_media "
                "WHERE mar.id_artist = ?";
        return Media::fetchAll( m_dbConnection, req, m_id );
    }
    else
    {
        // Not being able to rely on ForeignKey here makes me a saaaaad panda...
        // But sqlite only accepts "IS NULL" to compare against NULL...
        static const std::string req = "SELECT med.* FROM " + policy::MediaTable::Name + " med "
                "LEFT JOIN MediaArtistRelation mar ON mar.id_media = med.id_media "
                "WHERE mar.id_artist IS NULL";
        return Media::fetchAll( m_dbConnection, req );
    }
}

bool Artist::addMedia(Media* media)
{
    static const std::string req = "INSERT INTO MediaArtistRelation VALUES(?, ?)";
    // If track's ID is 0, the request will fail due to table constraints
    sqlite::ForeignKey artistForeignKey( m_id );
    return sqlite::Tools::executeRequest( m_dbConnection, req, media->id(), artistForeignKey );
}

const std::string& Artist::artworkUrl() const
{
    return m_artworkUrl;
}

bool Artist::setArtworkUrl( const std::string& artworkUrl )
{
    if ( m_artworkUrl == artworkUrl )
        return true;
    static const std::string req = "UPDATE " + policy::ArtistTable::Name +
            " SET artwork_url = ? WHERE id_artist = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, artworkUrl, m_id ) == false )
        return false;
    m_artworkUrl = artworkUrl;
    return true;
}

bool Artist::updateNbAlbum( int increment )
{
    assert( increment != 0 );
    assert( increment > 0 || ( increment < 0 && m_nbAlbums >= 1 ) );

    static const std::string req = "UPDATE " + policy::ArtistTable::Name +
            " SET nb_albums = nb_albums + ? WHERE id_artist = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, increment, m_id ) == false )
        return false;
    m_nbAlbums += increment;
    return true;
}

std::shared_ptr<Album> Artist::unknownAlbum()
{
    static const std::string req = "SELECT * FROM " + policy::AlbumTable::Name +
                        " WHERE artist_id = ? AND title IS NULL";
    auto album = Album::fetchOne( m_dbConnection, req, m_id );
    if ( album == nullptr )
    {
        album = Album::createUnknownAlbum( m_dbConnection, this );
        if ( album == nullptr )
            return nullptr;
        if ( updateNbAlbum( 1 ) == false )
        {
            Album::destroy( m_dbConnection, album );
            return nullptr;
        }
    }
    return album;
}

bool Artist::createTable( DBConnection dbConnection )
{
    static const std::string req = "CREATE TABLE IF NOT EXISTS " +
            policy::ArtistTable::Name +
            "("
                "id_artist INTEGER PRIMARY KEY AUTOINCREMENT,"
                "name TEXT UNIQUE ON CONFLICT FAIL,"
                "shortbio TEXT,"
                "artwork_url TEXT,"
                "nb_albums UNSIGNED INT DEFAULT 0"
            ")";
    static const std::string reqRel = "CREATE TABLE IF NOT EXISTS MediaArtistRelation("
                "id_media INTEGER NOT NULL,"
                "id_artist INTEGER,"
                "PRIMARY KEY (id_media, id_artist),"
                "FOREIGN KEY(id_media) REFERENCES " + policy::MediaTable::Name +
                "(id_media) ON DELETE CASCADE,"
                "FOREIGN KEY(id_artist) REFERENCES " + policy::ArtistTable::Name + "("
                    + policy::ArtistTable::CacheColumn + ") ON DELETE CASCADE"
            ")";
    return sqlite::Tools::executeRequest( dbConnection, req ) &&
            sqlite::Tools::executeRequest( dbConnection, reqRel );
}

bool Artist::createDefaultArtists( DBConnection dbConnection )
{
    // Don't rely on Artist::create, since we want to insert or do nothing here.
    // This will skip the cache for those new entities, but they will be inserted soon enough anyway.
    static const std::string req = "INSERT OR IGNORE INTO " + policy::ArtistTable::Name +
            "(id_artist) VALUES(?),(?)";
    return sqlite::Tools::executeRequest( dbConnection, req, medialibrary::UnknownArtistID,
                                          medialibrary::VariousArtistID );
}

std::shared_ptr<Artist> Artist::create( DBConnection dbConnection, const std::string &name )
{
    auto artist = std::make_shared<Artist>( name );
    static const std::string req = "INSERT INTO " + policy::ArtistTable::Name +
            "(id_artist, name) VALUES(NULL, ?)";
    if ( _Cache::insert( dbConnection, artist, req, name ) == false )
        return nullptr;
    artist->m_dbConnection = dbConnection;
    return artist;
}

<|endoftext|>


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

#include "mswin.h"
#include "settings.h"
#include "resources.h"

struct settings_definition_t
{
  const TCHAR * registry_value_name;
  DWORD default_value;
};

const settings_definition_t settings_definitions [trackbar_count] = {
  { TEXT ("count"), 50, },
  { TEXT ("heat"), 50, },
  { TEXT ("speed"), 50, },
  { TEXT ("radius"), 50, },
};

const TCHAR * key_name = TEXT ("SOFTWARE\\Buster\\Polymorph");

inline void load (HKEY key, LPCTSTR value_name, DWORD & setting, DWORD maximum)
{
  DWORD type, value, size;
  size = sizeof (DWORD);
  LONG error = ::RegQueryValueEx (key, value_name, 0, & type, (LPBYTE) & value, & size);
  if (error == ERROR_SUCCESS && value <= maximum) setting = value;
}

NOINLINE void load_settings (settings_t & settings)
{
  for (unsigned i = 0; i != trackbar_count; ++ i) {
    settings.trackbar_pos [i] = settings_definitions [i].default_value;
  }

  HKEY key;
  LONG error = ::RegOpenKeyEx (HKEY_CURRENT_USER, key_name, 0, KEY_QUERY_VALUE, & key);
  if (error == ERROR_SUCCESS) {
    for (unsigned i = 0; i != trackbar_count; ++ i) {
      const TCHAR * name = settings_definitions [i].registry_value_name;
      load (key, name, settings.trackbar_pos [i], 100);
    }
    ::RegCloseKey (key);
  }
}

NOINLINE void save_settings (const settings_t & settings)
{
  HKEY key;
  LONG error = ::RegCreateKeyEx (HKEY_CURRENT_USER, key_name, 0, NULL, 0, KEY_SET_VALUE, NULL, & key, NULL);
  if (error == ERROR_SUCCESS) {
    for (unsigned i = 0; i != trackbar_count; ++ i) {
      const TCHAR * name = settings_definitions [i].registry_value_name;
      ::RegSetValueEx (key, name, 0, REG_DWORD, (const BYTE *) & settings.trackbar_pos [i], sizeof (DWORD));
    }
    ::RegCloseKey (key);
  }
}
<commit_msg>rotor.h: Refill to 80 columns.<commit_after>// Copyright 2012-2019 Richard Copley
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "mswin.h"
#include "settings.h"
#include "resources.h"

struct settings_definition_t
{
  const TCHAR * registry_value_name;
  DWORD default_value;
};

const settings_definition_t settings_definitions [trackbar_count] = {
  {TEXT ("count"), 50},
  {TEXT ("heat"), 50},
  {TEXT ("speed"), 50},
  {TEXT ("radius"), 50},
};

const TCHAR * key_name = TEXT ("SOFTWARE\\Buster\\Polymorph");

inline void load (HKEY key, LPCTSTR value_name, DWORD & setting, DWORD maximum)
{
  DWORD type, value, size;
  size = sizeof (DWORD);
  LONG error =
    ::RegQueryValueEx (key, value_name, 0, & type, (LPBYTE) & value, & size);
  if (error == ERROR_SUCCESS && value <= maximum) {
    setting = value;
  }
}

NOINLINE void load_settings (settings_t & settings)
{
  for (unsigned i = 0; i != trackbar_count; ++ i) {
    settings.trackbar_pos [i] = settings_definitions [i].default_value;
  }

  HKEY key;
  LONG error =
    ::RegOpenKeyEx (HKEY_CURRENT_USER, key_name, 0, KEY_QUERY_VALUE, & key);
  if (error == ERROR_SUCCESS) {
    for (unsigned i = 0; i != trackbar_count; ++ i) {
      const TCHAR * name = settings_definitions [i].registry_value_name;
      load (key, name, settings.trackbar_pos [i], 100);
    }
    ::RegCloseKey (key);
  }
}

NOINLINE void save_settings (const settings_t & settings)
{
  HKEY key;
  LONG error = ::RegCreateKeyEx (
    HKEY_CURRENT_USER, key_name, 0, NULL, 0, KEY_SET_VALUE, NULL, & key, NULL);
  if (error == ERROR_SUCCESS) {
    for (unsigned i = 0; i != trackbar_count; ++ i) {
      const TCHAR * name = settings_definitions [i].registry_value_name;
      ::RegSetValueEx (key, name, 0, REG_DWORD,
        (const BYTE *) & settings.trackbar_pos [i], sizeof (DWORD));
    }
    ::RegCloseKey (key);
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2012, Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <cassert>
#include <cstdarg>
#include <cstdlib>
#include <map>
#include <stack>
#include <string>

#include <amx/amx.h>
#include <amx/amxaux.h>

#include "amxdebuginfo.h"
#include "amxpathfinder.h"
#include "amxstacktrace.h"
#include "amxutils.h"
#include "compiler.h"
#include "configreader.h"
#include "crashdetect.h"
#include "fileutils.h"
#include "logprintf.h"
#include "npcall.h"
#include "os.h"
#include "stacktrace.h"

#define AMX_EXEC_GDK (-10)

static const char *kLogMessagePrefix = "[debug] ";
static const char *kServerConfig = "server.cfg";

bool crashdetect::errorCaught_ = false;
std::stack<NPCall*> crashdetect::npCalls_;
ConfigReader crashdetect::serverCfg(kServerConfig);
crashdetect::InstanceMap crashdetect::instances_;

// static
crashdetect *crashdetect::GetInstance(AMX *amx) {
	InstanceMap::const_iterator iterator = instances_.find(amx);
	if (iterator == instances_.end()) {
		crashdetect *c = new crashdetect(amx);
		instances_.insert(std::make_pair(amx, c));
		return c;
	}
	return iterator->second;
}

// static
void crashdetect::DestroyInstance(AMX *amx) {
	instances_.erase(amx);
}

// static
void crashdetect::SystemException(void *context) {
	if (!npCalls_.empty()) {
		AMX *amx = npCalls_.top()->amx();
		GetInstance(amx)->HandleException();
	} else {
		logprintf("Server crashed due to an unknown error");
	}
	PrintSystemBacktrace(context);
}

// static
void crashdetect::SystemInterrupt(void *context) {
	if (!npCalls_.empty()) {
		AMX *amx = npCalls_.top()->amx();
		GetInstance(amx)->HandleInterrupt();
	} else {
		logprintf("Server received interrupt signal");
	}
	PrintSystemBacktrace(context);
}

// static
void crashdetect::DieOrContinue() {
	if (serverCfg.GetOption("die_on_error", false)) {
		logprintf("Aborting...");
		std::exit(EXIT_FAILURE);
	}
}

crashdetect::crashdetect(AMX *amx)
	: amx_(amx)
	, amxhdr_(reinterpret_cast<AMX_HEADER*>(amx->base))
{
	AMXPathFinder pathFinder;
	pathFinder.AddSearchPath("gamemodes");
	pathFinder.AddSearchPath("filterscripts");

	// Read a list of additional search paths from AMX_PATH.
	const char *AMX_PATH = getenv("AMX_PATH");
	if (AMX_PATH != 0) {
		std::string var(AMX_PATH);
		std::string path;
		std::string::size_type begin = 0;
		while (begin < var.length()) {
			std::string::size_type end = var.find(fileutils::kNativePathListSepChar, begin);
			if (end == std::string::npos) {
				end = var.length();
			}
			path.assign(var.begin() + begin, var.begin() + end);
			if (!path.empty()) {
				pathFinder.AddSearchPath(path);
			}
			begin = end + 1;
		}
	}

	amxPath_ = pathFinder.FindAMX(amx_);
	amxName_ = fileutils::GetFileName(amxPath_);

	if (!amxPath_.empty() && AMXDebugInfo::IsPresent(amx_)) {
		debugInfo_.Load(amxPath_);
	}

	amx_->sysreq_d = 0;
	prevCallback_ = amx_->callback;
}

int crashdetect::DoAmxCallback(cell index, cell *result, cell *params) {
	NPCall call = NPCall::Native(amx_, index);

	npCalls_.push(&call);
	int retcode = prevCallback_(amx_, index, result, params);
	npCalls_.pop();

	return retcode;
}

int crashdetect::DoAmxExec(cell *retval, int index) {
	NPCall call = NPCall::Public(amx_, index);

	npCalls_.push(&call);

	int retcode = ::amx_Exec(amx_, retval, index);
	if (retcode != AMX_ERR_NONE && !errorCaught_) {
		amx_Error(amx_, index, retcode);
	} else {
		errorCaught_ = false;
	}

	npCalls_.pop();

	return retcode;
}

int crashdetect::DoAmxRelease(cell amx_addr, void *releaser) {
	if (amx_addr < amx_->hlw || amx_addr >= amx_->stk) {
		HandleReleaseError(amx_addr, releaser);
	}
	return amx_Release(amx_, amx_addr);
}

void crashdetect::HandleExecError(int index, int error) {
	crashdetect::errorCaught_ = true;

	if (error == AMX_ERR_INDEX && index == AMX_EXEC_GDK) {
		error = AMX_ERR_NONE;
		return;
	}

	logprintf("Run time error %d: \"%s\"", error, aux_StrError(error));

	switch (error) {
		case AMX_ERR_BOUNDS: {
			cell bound = *(reinterpret_cast<cell*>(amx_->cip + amx_->base + amxhdr_->cod + sizeof(cell)));
			cell index = amx_->pri;
			if (index < 0) {
				logprintf(" Accessing element at negative index %d", index);
			} else {
				logprintf(" Accessing element at index %d past array upper bound %d", index, bound);
			}
			break;
		}
		case AMX_ERR_NOTFOUND: {
			AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx_->base + amxhdr_->natives);
			int numNatives = 0;
			amx_NumNatives(amx_, &numNatives);
			for (int i = 0; i < numNatives; ++i) {
				if (natives[i].address == 0) {
					char *name = reinterpret_cast<char*>(natives[i].nameofs + amx_->base);
					logprintf(" %s", name);
				}
			}
			break;
		}
		case AMX_ERR_STACKERR:
			logprintf(" Stack pointer (STK) is 0x%X, heap pointer (HEA) is 0x%X", amx_->stk, amx_->hea);
			break;
		case AMX_ERR_STACKLOW:
			logprintf(" Stack pointer (STK) is 0x%X, stack top (STP) is 0x%X", amx_->stk, amx_->stp);
			break;
		case AMX_ERR_HEAPLOW:
			logprintf(" Heap pointer (HEA) is 0x%X, heap bottom (HLW) is 0x%X", amx_->hea, amx_->hlw);
			break;
		case AMX_ERR_INVINSTR: {
			cell opcode = *(reinterpret_cast<cell*>(amx_->cip + amx_->base + amxhdr_->cod));
			logprintf(" Unknown opcode 0x%x at address 0x%08X", opcode , amx_->cip);
			break;
		}
	}

	if (error != AMX_ERR_NOTFOUND &&
		error != AMX_ERR_INDEX &&
		error != AMX_ERR_CALLBACK &&
		error != AMX_ERR_INIT)
	{
		PrintAmxBacktrace();
	}

	std::string command = serverCfg.GetOption("run_on_error", std::string());
	if (!command.empty()) {
		std::system(command.c_str());
	}

	DieOrContinue();
}

void crashdetect::HandleException() {
	logprintf("Server crashed while executing %s", amxName_.c_str());
	PrintAmxBacktrace();
}

void crashdetect::HandleInterrupt() {
	logprintf("Server received interrupt signal while executing %s", amxName_.c_str());
	PrintAmxBacktrace();
}

void crashdetect::HandleReleaseError(cell address, void *releaser) {
	std::string plugin = fileutils::GetFileName(os::GetModulePathFromAddr(releaser));
	if (plugin.empty()) {
		plugin.assign("<unknown>");
	}
	logprintf("Bad heap release detected:");
	logprintf(" %s [%08x] is releasing memory at %08x which is out of heap", plugin.c_str(), releaser, address);
	PrintSystemBacktrace();
}

// static
void crashdetect::PrintAmxBacktrace() {
	if (npCalls_.empty()) {
		return;
	}

	AMX *topAmx = npCalls_.top()->amx();

	cell frm = topAmx->frm;
	cell cip = topAmx->cip;
	int level = 0;

	if (cip == 0) {
		return;
	}

	logprintf("AMX backtrace:");

	std::stack<NPCall*> npCalls = npCalls_;

	while (!npCalls.empty() && cip != 0) {
		const NPCall *call = npCalls.top();

		// We don't trace calls across AMX bounds i.e. outside of top-level
		// function's AMX instance.
		if (call->amx() != topAmx) {
			assert(level != 0);
			break;
		}

		if (call->IsNative()) {
			AMX_NATIVE address = amxutils::GetNativeAddress(call->amx(), call->index());
			if (address != 0) {
				std::string module = fileutils::GetFileName(os::GetModulePathFromAddr((void*)address));
				std::string from = " from " + module;
				if (module.empty()) {
					from.clear();
				}
				const char *name = amxutils::GetNativeName(call->amx(), call->index());
				if (name != 0) {
					logprintf("#%d native %s () [%08x]%s", level++, name, address, from.c_str());
				}
			}
		} else if (call->IsPublic()) {
			AMXDebugInfo &debugInfo = instances_[call->amx()]->debugInfo_;

			amxutils::PushStack(call->amx(), cip); // push return address
			amxutils::PushStack(call->amx(), frm); // push frame pointer
			frm = call->amx()->stk;

			AMXStackTrace trace(call->amx(), debugInfo, frm);
			std::deque<AMXStackFrame> frames = trace.GetFrames();

			frm = amxutils::PopStack(call->amx()); // pop frame pointer
			cip = amxutils::PopStack(call->amx()); // pop return address

			if (frames.empty()) {
				ucell epAddr = amxutils::GetPublicAddress(call->amx(), call->index());
				frames.push_front(AMXStackFrame(call->amx(), frm, 0, epAddr, debugInfo));
			} else {
				if (!debugInfo.IsLoaded()) {
					AMXStackFrame &bottom = frames.back();
					bottom = AMXStackFrame(call->amx(),
						bottom.GetFrameAddress(),
						bottom.GetReturnAddress(),
						amxutils::GetPublicAddress(call->amx(), call->index()),
						debugInfo);
				}
			}

			std::string &amxName = instances_[call->amx()]->amxName_;
			for (size_t i = 0; i < frames.size(); i++) {
				std::string from = " from " + amxName;
				if (amxName.empty() || debugInfo.IsLoaded()) {
					from.clear();
				}
				logprintf("#%d %s%s", level++, frames[i].GetString().c_str(), from.c_str());
			}

			frm = call->frm();
			cip = call->cip();
		}

		npCalls.pop();
	}
}

// static
void crashdetect::PrintSystemBacktrace(void *context) {
	logprintf("System backtrace:");

	int level = 0;

	StackTrace trace(context);
	std::deque<StackFrame> frames = trace.GetFrames();

	for (std::deque<StackFrame>::const_iterator iterator = frames.begin();
			iterator != frames.end(); ++iterator) {
		const StackFrame &frame = *iterator;

		std::string module = os::GetModulePathFromAddr(frame.GetReturnAddress());
		std::string from = " from " + module;
		if (module.empty()) {
			from.clear();
		}

		logprintf("#%d %s%s", level++, frame.GetString().c_str(), from.c_str());
	}
}

// static
void crashdetect::logprintf(const char *format, ...) {
	std::va_list args;
	va_start(args, format);

	std::string prefixed_format;
	prefixed_format.append(kLogMessagePrefix);
	prefixed_format.append(format);

	::vlogprintf(prefixed_format.c_str(), args);

	va_end(args);
}
<commit_msg>Get rid of pointless constants<commit_after>// Copyright (c) 2011-2012, Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <cassert>
#include <cstdarg>
#include <cstdlib>
#include <map>
#include <stack>
#include <string>

#include <amx/amx.h>
#include <amx/amxaux.h>

#include "amxdebuginfo.h"
#include "amxpathfinder.h"
#include "amxstacktrace.h"
#include "amxutils.h"
#include "compiler.h"
#include "configreader.h"
#include "crashdetect.h"
#include "fileutils.h"
#include "logprintf.h"
#include "npcall.h"
#include "os.h"
#include "stacktrace.h"

#define AMX_EXEC_GDK (-10)

bool crashdetect::errorCaught_ = false;
std::stack<NPCall*> crashdetect::npCalls_;
ConfigReader crashdetect::serverCfg("server.cfg");
crashdetect::InstanceMap crashdetect::instances_;

// static
crashdetect *crashdetect::GetInstance(AMX *amx) {
	InstanceMap::const_iterator iterator = instances_.find(amx);
	if (iterator == instances_.end()) {
		crashdetect *c = new crashdetect(amx);
		instances_.insert(std::make_pair(amx, c));
		return c;
	}
	return iterator->second;
}

// static
void crashdetect::DestroyInstance(AMX *amx) {
	instances_.erase(amx);
}

// static
void crashdetect::SystemException(void *context) {
	if (!npCalls_.empty()) {
		AMX *amx = npCalls_.top()->amx();
		GetInstance(amx)->HandleException();
	} else {
		logprintf("Server crashed due to an unknown error");
	}
	PrintSystemBacktrace(context);
}

// static
void crashdetect::SystemInterrupt(void *context) {
	if (!npCalls_.empty()) {
		AMX *amx = npCalls_.top()->amx();
		GetInstance(amx)->HandleInterrupt();
	} else {
		logprintf("Server received interrupt signal");
	}
	PrintSystemBacktrace(context);
}

// static
void crashdetect::DieOrContinue() {
	if (serverCfg.GetOption("die_on_error", false)) {
		logprintf("Aborting...");
		std::exit(EXIT_FAILURE);
	}
}

crashdetect::crashdetect(AMX *amx)
	: amx_(amx)
	, amxhdr_(reinterpret_cast<AMX_HEADER*>(amx->base))
{
	AMXPathFinder pathFinder;
	pathFinder.AddSearchPath("gamemodes");
	pathFinder.AddSearchPath("filterscripts");

	// Read a list of additional search paths from AMX_PATH.
	const char *AMX_PATH = getenv("AMX_PATH");
	if (AMX_PATH != 0) {
		std::string var(AMX_PATH);
		std::string path;
		std::string::size_type begin = 0;
		while (begin < var.length()) {
			std::string::size_type end = var.find(fileutils::kNativePathListSepChar, begin);
			if (end == std::string::npos) {
				end = var.length();
			}
			path.assign(var.begin() + begin, var.begin() + end);
			if (!path.empty()) {
				pathFinder.AddSearchPath(path);
			}
			begin = end + 1;
		}
	}

	amxPath_ = pathFinder.FindAMX(amx_);
	amxName_ = fileutils::GetFileName(amxPath_);

	if (!amxPath_.empty() && AMXDebugInfo::IsPresent(amx_)) {
		debugInfo_.Load(amxPath_);
	}

	amx_->sysreq_d = 0;
	prevCallback_ = amx_->callback;
}

int crashdetect::DoAmxCallback(cell index, cell *result, cell *params) {
	NPCall call = NPCall::Native(amx_, index);

	npCalls_.push(&call);
	int retcode = prevCallback_(amx_, index, result, params);
	npCalls_.pop();

	return retcode;
}

int crashdetect::DoAmxExec(cell *retval, int index) {
	NPCall call = NPCall::Public(amx_, index);

	npCalls_.push(&call);

	int retcode = ::amx_Exec(amx_, retval, index);
	if (retcode != AMX_ERR_NONE && !errorCaught_) {
		amx_Error(amx_, index, retcode);
	} else {
		errorCaught_ = false;
	}

	npCalls_.pop();

	return retcode;
}

int crashdetect::DoAmxRelease(cell amx_addr, void *releaser) {
	if (amx_addr < amx_->hlw || amx_addr >= amx_->stk) {
		HandleReleaseError(amx_addr, releaser);
	}
	return amx_Release(amx_, amx_addr);
}

void crashdetect::HandleExecError(int index, int error) {
	crashdetect::errorCaught_ = true;

	if (error == AMX_ERR_INDEX && index == AMX_EXEC_GDK) {
		error = AMX_ERR_NONE;
		return;
	}

	logprintf("Run time error %d: \"%s\"", error, aux_StrError(error));

	switch (error) {
		case AMX_ERR_BOUNDS: {
			cell bound = *(reinterpret_cast<cell*>(amx_->cip + amx_->base + amxhdr_->cod + sizeof(cell)));
			cell index = amx_->pri;
			if (index < 0) {
				logprintf(" Accessing element at negative index %d", index);
			} else {
				logprintf(" Accessing element at index %d past array upper bound %d", index, bound);
			}
			break;
		}
		case AMX_ERR_NOTFOUND: {
			AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx_->base + amxhdr_->natives);
			int numNatives = 0;
			amx_NumNatives(amx_, &numNatives);
			for (int i = 0; i < numNatives; ++i) {
				if (natives[i].address == 0) {
					char *name = reinterpret_cast<char*>(natives[i].nameofs + amx_->base);
					logprintf(" %s", name);
				}
			}
			break;
		}
		case AMX_ERR_STACKERR:
			logprintf(" Stack pointer (STK) is 0x%X, heap pointer (HEA) is 0x%X", amx_->stk, amx_->hea);
			break;
		case AMX_ERR_STACKLOW:
			logprintf(" Stack pointer (STK) is 0x%X, stack top (STP) is 0x%X", amx_->stk, amx_->stp);
			break;
		case AMX_ERR_HEAPLOW:
			logprintf(" Heap pointer (HEA) is 0x%X, heap bottom (HLW) is 0x%X", amx_->hea, amx_->hlw);
			break;
		case AMX_ERR_INVINSTR: {
			cell opcode = *(reinterpret_cast<cell*>(amx_->cip + amx_->base + amxhdr_->cod));
			logprintf(" Unknown opcode 0x%x at address 0x%08X", opcode , amx_->cip);
			break;
		}
	}

	if (error != AMX_ERR_NOTFOUND &&
		error != AMX_ERR_INDEX &&
		error != AMX_ERR_CALLBACK &&
		error != AMX_ERR_INIT)
	{
		PrintAmxBacktrace();
	}

	std::string command = serverCfg.GetOption("run_on_error", std::string());
	if (!command.empty()) {
		std::system(command.c_str());
	}

	DieOrContinue();
}

void crashdetect::HandleException() {
	logprintf("Server crashed while executing %s", amxName_.c_str());
	PrintAmxBacktrace();
}

void crashdetect::HandleInterrupt() {
	logprintf("Server received interrupt signal while executing %s", amxName_.c_str());
	PrintAmxBacktrace();
}

void crashdetect::HandleReleaseError(cell address, void *releaser) {
	std::string plugin = fileutils::GetFileName(os::GetModulePathFromAddr(releaser));
	if (plugin.empty()) {
		plugin.assign("<unknown>");
	}
	logprintf("Bad heap release detected:");
	logprintf(" %s [%08x] is releasing memory at %08x which is out of heap", plugin.c_str(), releaser, address);
	PrintSystemBacktrace();
}

// static
void crashdetect::PrintAmxBacktrace() {
	if (npCalls_.empty()) {
		return;
	}

	AMX *topAmx = npCalls_.top()->amx();

	cell frm = topAmx->frm;
	cell cip = topAmx->cip;
	int level = 0;

	if (cip == 0) {
		return;
	}

	logprintf("AMX backtrace:");

	std::stack<NPCall*> npCalls = npCalls_;

	while (!npCalls.empty() && cip != 0) {
		const NPCall *call = npCalls.top();

		// We don't trace calls across AMX bounds i.e. outside of top-level
		// function's AMX instance.
		if (call->amx() != topAmx) {
			assert(level != 0);
			break;
		}

		if (call->IsNative()) {
			AMX_NATIVE address = amxutils::GetNativeAddress(call->amx(), call->index());
			if (address != 0) {
				std::string module = fileutils::GetFileName(os::GetModulePathFromAddr((void*)address));
				std::string from = " from " + module;
				if (module.empty()) {
					from.clear();
				}
				const char *name = amxutils::GetNativeName(call->amx(), call->index());
				if (name != 0) {
					logprintf("#%d native %s () [%08x]%s", level++, name, address, from.c_str());
				}
			}
		} else if (call->IsPublic()) {
			AMXDebugInfo &debugInfo = instances_[call->amx()]->debugInfo_;

			amxutils::PushStack(call->amx(), cip); // push return address
			amxutils::PushStack(call->amx(), frm); // push frame pointer
			frm = call->amx()->stk;

			AMXStackTrace trace(call->amx(), debugInfo, frm);
			std::deque<AMXStackFrame> frames = trace.GetFrames();

			frm = amxutils::PopStack(call->amx()); // pop frame pointer
			cip = amxutils::PopStack(call->amx()); // pop return address

			if (frames.empty()) {
				ucell epAddr = amxutils::GetPublicAddress(call->amx(), call->index());
				frames.push_front(AMXStackFrame(call->amx(), frm, 0, epAddr, debugInfo));
			} else {
				if (!debugInfo.IsLoaded()) {
					AMXStackFrame &bottom = frames.back();
					bottom = AMXStackFrame(call->amx(),
						bottom.GetFrameAddress(),
						bottom.GetReturnAddress(),
						amxutils::GetPublicAddress(call->amx(), call->index()),
						debugInfo);
				}
			}

			std::string &amxName = instances_[call->amx()]->amxName_;
			for (size_t i = 0; i < frames.size(); i++) {
				std::string from = " from " + amxName;
				if (amxName.empty() || debugInfo.IsLoaded()) {
					from.clear();
				}
				logprintf("#%d %s%s", level++, frames[i].GetString().c_str(), from.c_str());
			}

			frm = call->frm();
			cip = call->cip();
		}

		npCalls.pop();
	}
}

// static
void crashdetect::PrintSystemBacktrace(void *context) {
	logprintf("System backtrace:");

	int level = 0;

	StackTrace trace(context);
	std::deque<StackFrame> frames = trace.GetFrames();

	for (std::deque<StackFrame>::const_iterator iterator = frames.begin();
			iterator != frames.end(); ++iterator) {
		const StackFrame &frame = *iterator;

		std::string module = os::GetModulePathFromAddr(frame.GetReturnAddress());
		std::string from = " from " + module;
		if (module.empty()) {
			from.clear();
		}

		logprintf("#%d %s%s", level++, frame.GetString().c_str(), from.c_str());
	}
}

// static
void crashdetect::logprintf(const char *format, ...) {
	std::va_list args;
	va_start(args, format);

	std::string prefixed_format;
	prefixed_format.append("[debug] ");
	prefixed_format.append(format);

	::vlogprintf(prefixed_format.c_str(), args);

	va_end(args);
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2014 Dmitry Tsvettsikh <https://github.com/reklatsmasters>
 *
 * MIT License <https://github.com/reklatsmasters/node-process-list/blob/master/LICENSE>
 */

#include "snapshot.h"  // NOLINT(build/include)

#include <nan.h>

#include <algorithm>
#include <memory>

#include "tasklist.h"  // NOLINT(build/include)

using v8::Number;
using v8::String;
using v8::Array;
using v8::Object;
using v8::Array;
using v8::Function;
using v8::Local;
using v8::Value;
using v8::Date;
using pl::process_fields;

#define STR(s) Nan::New<v8::String>(s).ToLocalChecked()

#define PROP_BOOL(obj, prop) \
  Nan::To<bool>(Nan::Get(obj, STR(prop)).ToLocalChecked()).FromJust()

class SnapshotWorker : public Nan::AsyncWorker {
 public:
  SnapshotWorker(Nan::Callback *callback, const struct process_fields &fields)
  : Nan::AsyncWorker(callback), psfields(fields) {
  }

  ~SnapshotWorker() {}

  void Execute() {
    try {
      tasks = pl::list(psfields);
    } catch(const std::exception &e) {
      SetErrorMessage(e.what());
    }
  }

  void HandleOKCallback() {
    Nan::HandleScope scope;

    Local<Array> jobs = Nan::New<Array>(tasks.size());

    for (uint32_t i = 0; i < jobs->Length(); ++i) {
      Local<Object> hash = Nan::New<Object>();

      if (psfields.name) {
        Nan::Set(hash, STR("name"), STR(tasks.at(i).name));
      }

      if (psfields.pid) {
        Nan::Set(hash, STR("pid"), Nan::New<Number>(tasks.at(i).pid));
      }

      if (psfields.ppid) {
        Nan::Set(hash, STR("ppid"), Nan::New<Number>(tasks.at(i).ppid));
      }

      if (psfields.path) {
        Nan::Set(hash, STR("path"), STR(tasks.at(i).path));
      }

      if (psfields.threads) {
        Nan::Set(hash, STR("threads"),
          Nan::New<Number>(tasks.at(i).threads));
      }

      if (psfields.owner) {
        Nan::Set(hash, STR("owner"), STR(tasks.at(i).owner));
      }

      if (psfields.priority) {
        Nan::Set(hash, STR("priority"),
          Nan::New<Number>(tasks.at(i).priority));
      }

      if (psfields.cmdline) {
        Nan::Set(hash, STR("cmdline"), STR(tasks.at(i).cmdline));
      }

      if (psfields.starttime) {
        Nan::Set(hash, STR("starttime"),
          Nan::New<Date>(tasks.at(i).starttime).ToLocalChecked());
      }

      if (psfields.vmem) {
        Nan::Set(hash, STR("vmem"),
          Nan::New<Number>(tasks.at(i).vmem));
      }

      if (psfields.pmem) {
        Nan::Set(hash, STR("pmem"),
          Nan::New<Number>(tasks.at(i).pmem));
      }

      Nan::Set(jobs, i, hash);
    }

    Local<Value> argv[] = {
      Nan::Null(),
      jobs
    };

    callback->Call(2, argv);
  }

  void HandleErrorCallback() {
    Nan::HandleScope scope;

    Local<Value> argv[] = {
      Nan::Error(ErrorMessage())
    };

    callback->Call(1, argv);
  }

 private:
  pl::list_t tasks;
  process_fields psfields;
};

NAN_METHOD(snapshot) {
  auto arg0 = info[0].As<Object>();

  struct process_fields fields = {
    PROP_BOOL(arg0, "pid"),
    PROP_BOOL(arg0, "ppid"),
    PROP_BOOL(arg0, "path"),
    PROP_BOOL(arg0, "name"),
    PROP_BOOL(arg0, "owner"),
    PROP_BOOL(arg0, "cmdline"),
    PROP_BOOL(arg0, "threads"),
    PROP_BOOL(arg0, "priority"),
    PROP_BOOL(arg0, "starttime"),
    PROP_BOOL(arg0, "vmem"),
    PROP_BOOL(arg0, "pmem")
  };

  auto *callback = new Nan::Callback(info[1].As<Function>());

  Nan::AsyncQueueWorker(new SnapshotWorker(callback, fields));
}
<commit_msg>`vmem` and `pmem` now is string It's uint64_t values.<commit_after>/**
 * Copyright (c) 2014 Dmitry Tsvettsikh <https://github.com/reklatsmasters>
 *
 * MIT License <https://github.com/reklatsmasters/node-process-list/blob/master/LICENSE>
 */

#include "snapshot.h"  // NOLINT(build/include)

#include <nan.h>

#include <algorithm>
#include <memory>

#include "tasklist.h"  // NOLINT(build/include)

using v8::Number;
using v8::String;
using v8::Array;
using v8::Object;
using v8::Array;
using v8::Function;
using v8::Local;
using v8::Value;
using v8::Date;
using pl::process_fields;

#define STR(s) Nan::New<v8::String>(s).ToLocalChecked()

#define PROP_BOOL(obj, prop) \
  Nan::To<bool>(Nan::Get(obj, STR(prop)).ToLocalChecked()).FromJust()

class SnapshotWorker : public Nan::AsyncWorker {
 public:
  SnapshotWorker(Nan::Callback *callback, const struct process_fields &fields)
  : Nan::AsyncWorker(callback), psfields(fields) {
  }

  ~SnapshotWorker() {}

  void Execute() {
    try {
      tasks = pl::list(psfields);
    } catch(const std::exception &e) {
      SetErrorMessage(e.what());
    }
  }

  void HandleOKCallback() {
    Nan::HandleScope scope;

    Local<Array> jobs = Nan::New<Array>(tasks.size());

    for (uint32_t i = 0; i < jobs->Length(); ++i) {
      Local<Object> hash = Nan::New<Object>();

      if (psfields.name) {
        Nan::Set(hash, STR("name"), STR(tasks.at(i).name));
      }

      if (psfields.pid) {
        Nan::Set(hash, STR("pid"), Nan::New<Number>(tasks.at(i).pid));
      }

      if (psfields.ppid) {
        Nan::Set(hash, STR("ppid"), Nan::New<Number>(tasks.at(i).ppid));
      }

      if (psfields.path) {
        Nan::Set(hash, STR("path"), STR(tasks.at(i).path));
      }

      if (psfields.threads) {
        Nan::Set(hash, STR("threads"),
          Nan::New<Number>(tasks.at(i).threads));
      }

      if (psfields.owner) {
        Nan::Set(hash, STR("owner"), STR(tasks.at(i).owner));
      }

      if (psfields.priority) {
        Nan::Set(hash, STR("priority"),
          Nan::New<Number>(tasks.at(i).priority));
      }

      if (psfields.cmdline) {
        Nan::Set(hash, STR("cmdline"), STR(tasks.at(i).cmdline));
      }

      if (psfields.starttime) {
        Nan::Set(hash, STR("starttime"),
          Nan::New<Date>(tasks.at(i).starttime).ToLocalChecked());
      }

      if (psfields.vmem) {
        Nan::Set(hash, STR("vmem"), STR(std::to_string(tasks.at(i).vmem)));
      }

      if (psfields.pmem) {
        Nan::Set(hash, STR("pmem"), STR(std::to_string(tasks.at(i).pmem)));
      }

      Nan::Set(jobs, i, hash);
    }

    Local<Value> argv[] = {
      Nan::Null(),
      jobs
    };

    callback->Call(2, argv);
  }

  void HandleErrorCallback() {
    Nan::HandleScope scope;

    Local<Value> argv[] = {
      Nan::Error(ErrorMessage())
    };

    callback->Call(1, argv);
  }

 private:
  pl::list_t tasks;
  process_fields psfields;
};

NAN_METHOD(snapshot) {
  auto arg0 = info[0].As<Object>();

  struct process_fields fields = {
    PROP_BOOL(arg0, "pid"),
    PROP_BOOL(arg0, "ppid"),
    PROP_BOOL(arg0, "path"),
    PROP_BOOL(arg0, "name"),
    PROP_BOOL(arg0, "owner"),
    PROP_BOOL(arg0, "cmdline"),
    PROP_BOOL(arg0, "threads"),
    PROP_BOOL(arg0, "priority"),
    PROP_BOOL(arg0, "starttime"),
    PROP_BOOL(arg0, "vmem"),
    PROP_BOOL(arg0, "pmem")
  };

  auto *callback = new Nan::Callback(info[1].As<Function>());

  Nan::AsyncQueueWorker(new SnapshotWorker(callback, fields));
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
//USA

#ifndef JUBATUS_CORE_FRAMEWORK_PUSH_MIXABLE_HPP_
#define JUBATUS_CORE_FRAMEWORK_PUSH_MIXABLE_HPP_

#include "mixable.hpp"
#include "packer.hpp"
#include "../common/version.hpp"

namespace jubatus {
namespace core {
namespace framework {

// public interface for Jubatus users
class push_mixable : public virtual mixable {
 public:
  push_mixable();
  virtual ~push_mixable();

  virtual void get_argument(packer&) const = 0;
  virtual void pull(const msgpack::object& arg, packer&) const = 0;
  virtual void push(const msgpack::object&) = 0;
};

}  // namespace framework
}  // namespace core
}  // namespace jubatus

#endif  // JUBATUS_CORE_FRAMEWORK_PUSH_MIXABLE_HPP_
<commit_msg>Fix license term in push_mixable<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2014 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#ifndef JUBATUS_CORE_FRAMEWORK_PUSH_MIXABLE_HPP_
#define JUBATUS_CORE_FRAMEWORK_PUSH_MIXABLE_HPP_

#include "mixable.hpp"
#include "packer.hpp"
#include "../common/version.hpp"

namespace jubatus {
namespace core {
namespace framework {

// public interface for Jubatus users
class push_mixable : public virtual mixable {
 public:
  push_mixable();
  virtual ~push_mixable();

  virtual void get_argument(packer&) const = 0;
  virtual void pull(const msgpack::object& arg, packer&) const = 0;
  virtual void push(const msgpack::object&) = 0;
};

}  // namespace framework
}  // namespace core
}  // namespace jubatus

#endif  // JUBATUS_CORE_FRAMEWORK_PUSH_MIXABLE_HPP_
<|endoftext|>


<commit_before>#include "communique/Client.h"

#include <mutex>
#include <future>
#include "communique/impl/Exceptions.h"

#define _WEBSOCKETPP_CPP11_STL_ // Make sure websocketpp uses c++11 features in preference to boost ones
#include <websocketpp/client.hpp>
#include <websocketpp/config/asio.hpp>
#include "communique/impl/Connection.h"

//
// Declaration of the pimple
//
namespace communique
{
	class ClientPrivateMembers
	{
	public:
		typedef websocketpp::client<websocketpp::config::asio_tls> client_type;
		std::thread ioThread_;
		client_type client_;
		std::unique_ptr<communique::impl::Connection> pConnection_;
		std::string verifyFilename_;

		std::function<void(const std::string&)> infoHandler_;
		std::function<void(const std::string&,communique::IConnection*)> infoHandlerAdvanced_;
		std::function<std::string(const std::string&)> requestHandler_;
		std::function<std::string(const std::string&,communique::IConnection*)> requestHandlerAdvanced_;

		std::shared_ptr<boost::asio::ssl::context> on_tls_init( websocketpp::connection_hdl hdl );
//		void on_message( websocketpp::connection_hdl hdl, client_type::message_ptr msg );
		void on_open( websocketpp::connection_hdl hdl );
		void on_close( websocketpp::connection_hdl hdl );
		void on_interrupt( websocketpp::connection_hdl hdl );
	};
}

communique::Client::Client()
	: pImple_( new ClientPrivateMembers )
{
	pImple_->client_.set_access_channels(websocketpp::log::alevel::none);
	//pImple_->client_.set_error_channels(websocketpp::log::elevel::all ^ websocketpp::log::elevel::info);
	pImple_->client_.set_error_channels(websocketpp::log::elevel::none);
	pImple_->client_.set_tls_init_handler( std::bind( &ClientPrivateMembers::on_tls_init, pImple_.get(), std::placeholders::_1 ) );
	pImple_->client_.init_asio();
//	pImple_->client_.set_message_handler( std::bind( &ClientPrivateMembers::on_message, pImple_.get(), std::placeholders::_1, std::placeholders::_2 ) );
	pImple_->client_.set_open_handler( std::bind( &ClientPrivateMembers::on_open, pImple_.get(), std::placeholders::_1 ) );
	pImple_->client_.set_close_handler( std::bind( &ClientPrivateMembers::on_close, pImple_.get(), std::placeholders::_1 ) );
	pImple_->client_.set_interrupt_handler( std::bind( &ClientPrivateMembers::on_interrupt, pImple_.get(), std::placeholders::_1 ) );
}

communique::Client::Client( Client&& otherClient ) noexcept
	: pImple_( std::move(otherClient.pImple_) )
{
	// No operation, everything done in initialiser list
}

communique::Client::~Client()
{
	try
	{
		// If std::move is used then pImple_ can be null, in which
		// case I don't want to do any cleanup.
		if( pImple_ ) disconnect();
	}
	catch(...) { /* Make sure no exceptions propagate out */ }
}

std::shared_ptr<boost::asio::ssl::context> communique::ClientPrivateMembers::on_tls_init( websocketpp::connection_hdl hdl )
{
	websocketpp::lib::shared_ptr<boost::asio::ssl::context> pContext( new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1) );
	pContext->set_options( boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use );

	if( !verifyFilename_.empty() )
	{
		pContext->load_verify_file( verifyFilename_ );
		pContext->set_verify_mode( boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert );
	}

	return pContext;
}

void communique::Client::connect( const std::string& URI )
{
	websocketpp::lib::error_code errorCode;
	auto pWebPPConnection=pImple_->client_.get_connection( URI, errorCode );
	if( errorCode.value()!=0 ) throw std::runtime_error( "Unable to get the websocketpp connection - "+errorCode.message() );
	pImple_->pConnection_.reset( new communique::impl::Connection( pWebPPConnection, pImple_->infoHandler_, pImple_->requestHandler_ ) );
	// If "advanced" handlers have beed set (just has IConnection* as additional argument)
	// change the handler to these.
	if( pImple_->infoHandlerAdvanced_ ) pImple_->pConnection_->setInfoHandler(pImple_->infoHandlerAdvanced_);
	if( pImple_->requestHandlerAdvanced_ ) pImple_->pConnection_->setRequestHandler(pImple_->requestHandlerAdvanced_);

	if( errorCode )
	{
		pImple_->client_.get_alog().write(websocketpp::log::alevel::app,errorCode.message());
		throw communique::impl::Exception( errorCode.message() );
	}

	pImple_->client_.connect( pImple_->pConnection_->underlyingPointer() );
	pImple_->ioThread_=std::thread( &ClientPrivateMembers::client_type::run, &pImple_->client_ );
}

bool communique::Client::isConnected()
{
	if( !pImple_->pConnection_ ) return false;
	return pImple_->pConnection_->isConnected();
}

void communique::Client::disconnect()
{
	if( pImple_->pConnection_ ) pImple_->pConnection_->close();
	if( pImple_->ioThread_.joinable() ) pImple_->ioThread_.join();
}

void communique::Client::verifyFilename( const std::string& filename )
{
	pImple_->verifyFilename_=filename;
}

void communique::Client::sendRequest( const std::string& message, std::function<void(const std::string&)> responseHandler )
{
	if( !pImple_->pConnection_ ) throw communique::impl::Exception( "No connection" );
	pImple_->pConnection_->sendRequest( message, responseHandler );
}

void communique::Client::sendInfo( const std::string& message )
{
	if( pImple_->pConnection_ ) throw communique::impl::Exception( "No connection" );
	pImple_->pConnection_->sendInfo( message );
}

void communique::Client::setInfoHandler( std::function<void(const std::string&)> infoHandler )
{
	pImple_->infoHandler_=infoHandler;
	pImple_->infoHandlerAdvanced_=nullptr;
	if( pImple_->pConnection_ )
	{
		pImple_->pConnection_->setInfoHandler( infoHandler );
	}
}

void communique::Client::setInfoHandler( std::function<void(const std::string&,communique::IConnection*)> infoHandler )
{
	pImple_->infoHandler_=nullptr;
	pImple_->infoHandlerAdvanced_=infoHandler;
	if( pImple_->pConnection_ )
	{
		pImple_->pConnection_->setInfoHandler( infoHandler );
	}
}

void communique::Client::setRequestHandler( std::function<std::string(const std::string&)> requestHandler )
{
	pImple_->requestHandler_=requestHandler;
	pImple_->requestHandlerAdvanced_=nullptr;
	if( pImple_->pConnection_ )
	{
		pImple_->pConnection_->setRequestHandler( requestHandler );
	}
}

void communique::Client::setRequestHandler( std::function<std::string(const std::string&,communique::IConnection*)> requestHandler )
{
	pImple_->requestHandler_=nullptr;
	pImple_->requestHandlerAdvanced_=requestHandler;
	if( pImple_->pConnection_ )
	{
		pImple_->pConnection_->setRequestHandler( requestHandler );
	}
}

//void communique::ClientPrivateMembers::on_message( websocketpp::connection_hdl hdl, client_type::message_ptr msg )
//{
//	communique::MessageHeader messageHeader;
//	messageHeader.ParseFromString( msg->get_payload() );
//
//	if( messageHeader.type()==communique::MessageHeader::INFO )
//	{
//		if( infoHandler_ ) infoHandler_( msg->get_payload().substr(messageHeader.ByteSize()) );
//	}
//	else if( messageHeader.type()==communique::MessageHeader::REQUEST )
//	{
//		if( requestHandler_ && messageHeader.has_user_reference() )
//		{
//			// Record where the message header stops and the body starts
//			size_t messageBodyOffset=messageHeader.ByteSize();
//
//			// Reuse the message header and stream out as a string
//			messageHeader.set_type( communique::MessageHeader::RESPONSE );
//			// The user reference will already be set correctly
//			std::string headerString;
//			messageHeader.SerializeToString( &headerString );
//
//			std::async( [ this, hdl, msg, messageBodyOffset, headerString ]()
//			{
//				// Send the rest of the message with the header stripped off first, and use the
//				// return from the handler
//				client_.send( hdl, headerString+requestHandler_( msg->get_payload().substr(messageBodyOffset) ), websocketpp::frame::opcode::BINARY );
//			} );
//		}
//	}
//	else if( messageHeader.type()==communique::MessageHeader::RESPONSE )
//	{
//		// This will be the response to a request that I've sent out, so
//		// I need to search for the handler that was stored when the message
//		// was sent.
//
//		// TODO - implement
//	}
//}
//
void communique::ClientPrivateMembers::on_open( websocketpp::connection_hdl hdl )
{
}

void communique::ClientPrivateMembers::on_close( websocketpp::connection_hdl hdl )
{
}

void communique::ClientPrivateMembers::on_interrupt( websocketpp::connection_hdl hdl )
{
	std::cout << "Connection has been interrupted" << std::endl;
}
<commit_msg>Correct accidental inversion of test logic<commit_after>#include "communique/Client.h"

#include <mutex>
#include <future>
#include "communique/impl/Exceptions.h"

#define _WEBSOCKETPP_CPP11_STL_ // Make sure websocketpp uses c++11 features in preference to boost ones
#include <websocketpp/client.hpp>
#include <websocketpp/config/asio.hpp>
#include "communique/impl/Connection.h"

//
// Declaration of the pimple
//
namespace communique
{
	class ClientPrivateMembers
	{
	public:
		typedef websocketpp::client<websocketpp::config::asio_tls> client_type;
		std::thread ioThread_;
		client_type client_;
		std::unique_ptr<communique::impl::Connection> pConnection_;
		std::string verifyFilename_;

		std::function<void(const std::string&)> infoHandler_;
		std::function<void(const std::string&,communique::IConnection*)> infoHandlerAdvanced_;
		std::function<std::string(const std::string&)> requestHandler_;
		std::function<std::string(const std::string&,communique::IConnection*)> requestHandlerAdvanced_;

		std::shared_ptr<boost::asio::ssl::context> on_tls_init( websocketpp::connection_hdl hdl );
//		void on_message( websocketpp::connection_hdl hdl, client_type::message_ptr msg );
		void on_open( websocketpp::connection_hdl hdl );
		void on_close( websocketpp::connection_hdl hdl );
		void on_interrupt( websocketpp::connection_hdl hdl );
	};
}

communique::Client::Client()
	: pImple_( new ClientPrivateMembers )
{
	pImple_->client_.set_access_channels(websocketpp::log::alevel::none);
	//pImple_->client_.set_error_channels(websocketpp::log::elevel::all ^ websocketpp::log::elevel::info);
	pImple_->client_.set_error_channels(websocketpp::log::elevel::none);
	pImple_->client_.set_tls_init_handler( std::bind( &ClientPrivateMembers::on_tls_init, pImple_.get(), std::placeholders::_1 ) );
	pImple_->client_.init_asio();
//	pImple_->client_.set_message_handler( std::bind( &ClientPrivateMembers::on_message, pImple_.get(), std::placeholders::_1, std::placeholders::_2 ) );
	pImple_->client_.set_open_handler( std::bind( &ClientPrivateMembers::on_open, pImple_.get(), std::placeholders::_1 ) );
	pImple_->client_.set_close_handler( std::bind( &ClientPrivateMembers::on_close, pImple_.get(), std::placeholders::_1 ) );
	pImple_->client_.set_interrupt_handler( std::bind( &ClientPrivateMembers::on_interrupt, pImple_.get(), std::placeholders::_1 ) );
}

communique::Client::Client( Client&& otherClient ) noexcept
	: pImple_( std::move(otherClient.pImple_) )
{
	// No operation, everything done in initialiser list
}

communique::Client::~Client()
{
	try
	{
		// If std::move is used then pImple_ can be null, in which
		// case I don't want to do any cleanup.
		if( pImple_ ) disconnect();
	}
	catch(...) { /* Make sure no exceptions propagate out */ }
}

std::shared_ptr<boost::asio::ssl::context> communique::ClientPrivateMembers::on_tls_init( websocketpp::connection_hdl hdl )
{
	websocketpp::lib::shared_ptr<boost::asio::ssl::context> pContext( new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1) );
	pContext->set_options( boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use );

	if( !verifyFilename_.empty() )
	{
		pContext->load_verify_file( verifyFilename_ );
		pContext->set_verify_mode( boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert );
	}

	return pContext;
}

void communique::Client::connect( const std::string& URI )
{
	websocketpp::lib::error_code errorCode;
	auto pWebPPConnection=pImple_->client_.get_connection( URI, errorCode );
	if( errorCode.value()!=0 ) throw std::runtime_error( "Unable to get the websocketpp connection - "+errorCode.message() );
	pImple_->pConnection_.reset( new communique::impl::Connection( pWebPPConnection, pImple_->infoHandler_, pImple_->requestHandler_ ) );
	// If "advanced" handlers have beed set (just has IConnection* as additional argument)
	// change the handler to these.
	if( pImple_->infoHandlerAdvanced_ ) pImple_->pConnection_->setInfoHandler(pImple_->infoHandlerAdvanced_);
	if( pImple_->requestHandlerAdvanced_ ) pImple_->pConnection_->setRequestHandler(pImple_->requestHandlerAdvanced_);

	if( errorCode )
	{
		pImple_->client_.get_alog().write(websocketpp::log::alevel::app,errorCode.message());
		throw communique::impl::Exception( errorCode.message() );
	}

	pImple_->client_.connect( pImple_->pConnection_->underlyingPointer() );
	pImple_->ioThread_=std::thread( &ClientPrivateMembers::client_type::run, &pImple_->client_ );
}

bool communique::Client::isConnected()
{
	if( !pImple_->pConnection_ ) return false;
	return pImple_->pConnection_->isConnected();
}

void communique::Client::disconnect()
{
	if( pImple_->pConnection_ ) pImple_->pConnection_->close();
	if( pImple_->ioThread_.joinable() ) pImple_->ioThread_.join();
}

void communique::Client::verifyFilename( const std::string& filename )
{
	pImple_->verifyFilename_=filename;
}

void communique::Client::sendRequest( const std::string& message, std::function<void(const std::string&)> responseHandler )
{
	if( !pImple_->pConnection_ ) throw communique::impl::Exception( "No connection" );
	pImple_->pConnection_->sendRequest( message, responseHandler );
}

void communique::Client::sendInfo( const std::string& message )
{
	if( !pImple_->pConnection_ ) throw communique::impl::Exception( "No connection" );
	pImple_->pConnection_->sendInfo( message );
}

void communique::Client::setInfoHandler( std::function<void(const std::string&)> infoHandler )
{
	pImple_->infoHandler_=infoHandler;
	pImple_->infoHandlerAdvanced_=nullptr;
	if( pImple_->pConnection_ )
	{
		pImple_->pConnection_->setInfoHandler( infoHandler );
	}
}

void communique::Client::setInfoHandler( std::function<void(const std::string&,communique::IConnection*)> infoHandler )
{
	pImple_->infoHandler_=nullptr;
	pImple_->infoHandlerAdvanced_=infoHandler;
	if( pImple_->pConnection_ )
	{
		pImple_->pConnection_->setInfoHandler( infoHandler );
	}
}

void communique::Client::setRequestHandler( std::function<std::string(const std::string&)> requestHandler )
{
	pImple_->requestHandler_=requestHandler;
	pImple_->requestHandlerAdvanced_=nullptr;
	if( pImple_->pConnection_ )
	{
		pImple_->pConnection_->setRequestHandler( requestHandler );
	}
}

void communique::Client::setRequestHandler( std::function<std::string(const std::string&,communique::IConnection*)> requestHandler )
{
	pImple_->requestHandler_=nullptr;
	pImple_->requestHandlerAdvanced_=requestHandler;
	if( pImple_->pConnection_ )
	{
		pImple_->pConnection_->setRequestHandler( requestHandler );
	}
}

//void communique::ClientPrivateMembers::on_message( websocketpp::connection_hdl hdl, client_type::message_ptr msg )
//{
//	communique::MessageHeader messageHeader;
//	messageHeader.ParseFromString( msg->get_payload() );
//
//	if( messageHeader.type()==communique::MessageHeader::INFO )
//	{
//		if( infoHandler_ ) infoHandler_( msg->get_payload().substr(messageHeader.ByteSize()) );
//	}
//	else if( messageHeader.type()==communique::MessageHeader::REQUEST )
//	{
//		if( requestHandler_ && messageHeader.has_user_reference() )
//		{
//			// Record where the message header stops and the body starts
//			size_t messageBodyOffset=messageHeader.ByteSize();
//
//			// Reuse the message header and stream out as a string
//			messageHeader.set_type( communique::MessageHeader::RESPONSE );
//			// The user reference will already be set correctly
//			std::string headerString;
//			messageHeader.SerializeToString( &headerString );
//
//			std::async( [ this, hdl, msg, messageBodyOffset, headerString ]()
//			{
//				// Send the rest of the message with the header stripped off first, and use the
//				// return from the handler
//				client_.send( hdl, headerString+requestHandler_( msg->get_payload().substr(messageBodyOffset) ), websocketpp::frame::opcode::BINARY );
//			} );
//		}
//	}
//	else if( messageHeader.type()==communique::MessageHeader::RESPONSE )
//	{
//		// This will be the response to a request that I've sent out, so
//		// I need to search for the handler that was stored when the message
//		// was sent.
//
//		// TODO - implement
//	}
//}
//
void communique::ClientPrivateMembers::on_open( websocketpp::connection_hdl hdl )
{
}

void communique::ClientPrivateMembers::on_close( websocketpp::connection_hdl hdl )
{
}

void communique::ClientPrivateMembers::on_interrupt( websocketpp::connection_hdl hdl )
{
	std::cout << "Connection has been interrupted" << std::endl;
}
<|endoftext|>