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

Program:   NeuroLib (DTI command line tools)
Language:  C++
Date:      $Date: 2009/08/03 17:36:42 $
Version:   $Revision: 1.8 $
Author:    Casey Goodlett (gcasey@sci.utah.edu)

Copyright (c)  Casey Goodlett. All rights reserved.
See NeuroLibCopyright.txt or http://www.ia.unc.edu/dev/Copyright.htm for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// STL includes
#include <string>
#include <iostream>
#include <fstream>

// ITK includes
#include <itkDiffusionTensor3D.h>
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>
#include <itkTensorLinearInterpolateImageFunction.h>
#include <itkVectorLinearInterpolateImageFunction.h>
#include <itkVersion.h>

//#include "FiberCalculator.h"
#include "deformationfieldoperations.h"
#include "fiberio.h"
#include "dtitypes.h"
#include "fiberprocessCLP.h"

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

  if(fiberFile == "")
    {
      std::cerr << "A fiber file has to be specified" << std::endl;
      return EXIT_FAILURE;
    }
  const bool VERBOSE = verbose;

  // Reader fiber bundle
  GroupType::Pointer group = readFiberFile(fiberFile);

  DeformationImageType::Pointer deformationfield(NULL);
  if(hField != "")
    deformationfield = readDeformationField(hField, HField);
  else if(displacementField != "")
    deformationfield = readDeformationField(displacementField, Displacement);
  else
    deformationfield = NULL;

  typedef itk::VectorLinearInterpolateImageFunction<DeformationImageType, double> DeformationInterpolateType;
  DeformationInterpolateType::Pointer definterp(NULL);
  if(deformationfield)
  {
    definterp = DeformationInterpolateType::New();
    definterp->SetInputImage(deformationfield);
  } else {
    noWarp = true;
  }

  // Setup new fiber bundle group
  GroupType::Pointer newgroup = GroupType::New();
  newgroup->SetId(0);

  ChildrenListType* children = group->GetChildren(0);

  if(VERBOSE)
    std::cout << "Getting spacing" << std::endl;

  // Get Spacing and offset from group
  double spacing[3];
  if( noWarp )
  {
    newgroup->SetObjectToWorldTransform( group->GetObjectToWorldTransform() ) ;
    newgroup->ComputeObjectToParentTransform() ;
    for(unsigned int i =0; i < 3; i++)
    {
      spacing[i] = (group->GetSpacing())[i];
    }
  }
  else
  {
    spacing[0] = spacing[1] = spacing[2] = 1;
  }
  newgroup->SetSpacing(spacing);

  itk::Vector<double, 3> sooffset;
  for(unsigned int i = 0; i < 3; i++)
    sooffset[i] = (group->GetObjectToParentTransform()->GetOffset())[i];

  if(VERBOSE)
  {
    std::cout << "Group Spacing: " << spacing[0] << ", " << spacing[1] << ", " << spacing[2] << std::endl;
    std::cout << "Group Offset: " << sooffset[0] << ", " << sooffset[1]  << ", " << sooffset[2] << std::endl;
    std::cout << "deformationfield: '" << deformationfield << "'" << std::endl;
  }

  // Setup tensor file if available
  typedef itk::ImageFileReader<TensorImageType> TensorImageReader;
  typedef itk::TensorLinearInterpolateImageFunction<TensorImageType, double> TensorInterpolateType;
  TensorImageReader::Pointer tensorreader = NULL;
  TensorInterpolateType::Pointer tensorinterp = NULL;

  if(tensorVolume != "")
  {
    tensorreader = TensorImageReader::New();
    tensorinterp = TensorInterpolateType::New();

    tensorreader->SetFileName(tensorVolume);
    try
    {
      tensorreader->Update();
      tensorinterp->SetInputImage(tensorreader->GetOutput());
    }
    catch(itk::ExceptionObject exp)
    {
      std::cerr << exp << std::endl;
      return EXIT_FAILURE;
    }
  }

  if(VERBOSE)
    std::cout << "Starting Loop" << std::endl;

  ChildrenListType::iterator it;
  unsigned int id = 1;

  // Need to allocate an image to write into for creating
  // the fiber label map
  IntImageType::Pointer labelimage;
  if(voxelize != "")
  {
    if(tensorVolume == "")
    {
      std::cerr << "Must specify tensor file to copy image metadata for fiber voxelize." << std::endl;
      return EXIT_FAILURE;
    }
    //tensorreader->GetOutput();
    labelimage = IntImageType::New();
    labelimage->SetSpacing(tensorreader->GetOutput()->GetSpacing());
    labelimage->SetOrigin(tensorreader->GetOutput()->GetOrigin());
    labelimage->SetDirection(tensorreader->GetOutput()->GetDirection());
    labelimage->SetRegions(tensorreader->GetOutput()->GetLargestPossibleRegion());
    labelimage->Allocate();
    labelimage->FillBuffer(0);
  }

  // For each fiber
  for(it = children->begin(); it != children->end(); it++)
  {
    DTIPointListType pointlist = dynamic_cast<DTITubeType*>((*it).GetPointer())->GetPoints();
    DTITubeType::Pointer newtube = DTITubeType::New();
    DTIPointListType newpoints;

    DTIPointListType::iterator pit;

    typedef DeformationInterpolateType::ContinuousIndexType ContinuousIndexType;
    ContinuousIndexType tensor_ci, def_ci ;
    // For each point along the fiber
//std::cout<<"plop"<<std::endl;
    for(pit = pointlist.begin(); pit != pointlist.end(); ++pit)
    {
      typedef DTIPointType::PointType PointType;
//      std::cout<<"plop3"<<std::endl;
      // p is not really a point its a continuous index
      const PointType p = pit->GetPosition();
      DTITubeType::TransformPointer transform = ((*it).GetPointer())->GetObjectToWorldTransform() ;
      const PointType p_world_orig = transform->TransformPoint( p ) ;
//      std::cout<<p_world_orig<<" "<<p<<std::endl;
      itk::Point<double, 3> pt_trans = p_world_orig ;
      if(deformationfield)
      {
        deformationfield->TransformPhysicalPointToContinuousIndex(p_world_orig, def_ci);

        if( !deformationfield->GetLargestPossibleRegion().IsInside( def_ci ) )
        {
          std::cerr << "Fiber is outside deformation field image. Deformation field has to be in the fiber space. Warning: Original position will be used" << std::endl ;
        }
        else
        {
          DeformationPixelType warp(definterp->EvaluateAtContinuousIndex(def_ci).GetDataPointer());
          for( int i = 0 ; i < 3 ; i++ )
          {
            pt_trans[ i ] += warp[ i ] ;
          }
//          deformationfield->TransformContinuousIndexToPhysicalPoint( def_ci , pt_trans ) ;
//          std::cout<<p << " "<< p_world_orig<<" "<<pt_trans<<std::endl;
        }
      }
//            std::cout<<"plop6"<<std::endl;

      if(voxelize != "")
      {
//        std::cout<<p << " "<< p_world_orig<<" "<<pt_trans<<std::endl;
        ContinuousIndexType cind;
        itk::Index<3> ind;
        labelimage->TransformPhysicalPointToContinuousIndex(pt_trans, cind);
        ind[0] = static_cast<long int>(vnl_math_rnd_halfinttoeven(cind[0]));
        ind[1] = static_cast<long int>(vnl_math_rnd_halfinttoeven(cind[1]));
        ind[2] = static_cast<long int>(vnl_math_rnd_halfinttoeven(cind[2]));

        if(!labelimage->GetLargestPossibleRegion().IsInside(ind))
        {
          std::cerr << "Error index: " << ind << " not in image"  << std::endl;
          std::cout << "Ignoring" << std::endl;
          //return EXIT_FAILURE;
	}
        if(voxelizeCountFibers)
        {
          labelimage->SetPixel(ind, labelimage->GetPixel(ind) + 1);
	}
        else
        {
          labelimage->SetPixel(ind, voxelLabel);
	}
      }

      DTIPointType newpoint;
      if(noDataChange==true)
	newpoint = *pit;
      // Should not have to do this
      if(noWarp)
      {
//        std::cout<<"no warp"<<std::endl;
	newpoint.SetPosition(p);
      }
      else
      {
	//set the point to world coordinate system and set the spacing to 1
//        std::cout<<"warp"<<std::endl;
	newpoint.SetPosition(pt_trans);
      }

      //newpoint.SetRadius(.4);
      //newpoint.SetRed(0.0);
      //newpoint.SetGreen(1.0);
      //newpoint.SetBlue(0.0);

      // Attribute tensor data if provided
      if(tensorVolume != "" && fiberOutput != "" && !noDataChange)
      {
	tensorreader->GetOutput()->TransformPhysicalPointToContinuousIndex(pt_trans, tensor_ci);
	itk::DiffusionTensor3D<double> tensor(tensorinterp->EvaluateAtContinuousIndex(tensor_ci).GetDataPointer());

	// TODO: Change SpatialObject interface to accept DiffusionTensor3D
	float sotensor[6];
	for(unsigned int i = 0; i < 6; ++i)
	  sotensor[i] = tensor[i];

	typedef itk::DiffusionTensor3D<double>::EigenValuesArrayType EigenValuesType;
	EigenValuesType eigenvalues;
	tensor.ComputeEigenValues(eigenvalues);

	newpoint.SetRadius(0.5);
	newpoint.SetTensorMatrix(sotensor);
	newpoint.AddField(itk::DTITubeSpatialObjectPoint<3>::FA, tensor.GetFractionalAnisotropy());
	newpoint.AddField("md", tensor.GetTrace()/3);
	newpoint.AddField("fro", sqrt(tensor[0]*tensor[0] +
				      2*tensor[1]*tensor[1] +
				      2*tensor[2]*tensor[2] +
				      tensor[3]*tensor[3] +
				      2*tensor[4]*tensor[4] +
				      tensor[5]*tensor[5]));
	newpoint.AddField("l1", eigenvalues[2]);
	newpoint.AddField("l2", eigenvalues[1]);
	newpoint.AddField("l3", eigenvalues[0]);
      }

      newpoints.push_back(newpoint);
    }
    newtube->SetSpacing(spacing);
    newtube->SetId(id++);
    newtube->SetPoints(newpoints);
    newgroup->AddSpatialObject(newtube);
  }
//  std::cout<<"plop2"<<std::endl;

  if(VERBOSE)
    std::cout << "Ending Loop" << std::endl;

  if(VERBOSE)
    std::cout << "Output: " << fiberOutput << std::endl;

  if(fiberOutput != "")
    writeFiberFile(fiberOutput, newgroup);

  if(voxelize != "")
  {
    typedef itk::ImageFileWriter<IntImageType> LabelWriter;
    LabelWriter::Pointer writer = LabelWriter::New();
    writer->SetInput(labelimage);
    writer->SetFileName(voxelize);
    writer->UseCompressionOn();
    try
    {
      writer->Update();
    }
    catch(itk::ExceptionObject & e)
    {
      std::cerr << e.what() << std::endl;
      return EXIT_FAILURE;
    }
  }

  delete children;
  return EXIT_SUCCESS;
}
<commit_msg>BUG: fix processing with verbose mode ON when no deformation field is used<commit_after>/*=========================================================================

Program:   NeuroLib (DTI command line tools)
Language:  C++
Date:      $Date: 2009/08/03 17:36:42 $
Version:   $Revision: 1.8 $
Author:    Casey Goodlett (gcasey@sci.utah.edu)

Copyright (c)  Casey Goodlett. All rights reserved.
See NeuroLibCopyright.txt or http://www.ia.unc.edu/dev/Copyright.htm for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// STL includes
#include <string>
#include <iostream>
#include <fstream>

// ITK includes
#include <itkDiffusionTensor3D.h>
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>
#include <itkTensorLinearInterpolateImageFunction.h>
#include <itkVectorLinearInterpolateImageFunction.h>
#include <itkVersion.h>

//#include "FiberCalculator.h"
#include "deformationfieldoperations.h"
#include "fiberio.h"
#include "dtitypes.h"
#include "fiberprocessCLP.h"

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

  if(fiberFile == "")
    {
      std::cerr << "A fiber file has to be specified" << std::endl;
      return EXIT_FAILURE;
    }
  const bool VERBOSE = verbose;

  // Reader fiber bundle
  GroupType::Pointer group = readFiberFile(fiberFile);

  DeformationImageType::Pointer deformationfield(NULL);
  if(hField != "")
    deformationfield = readDeformationField(hField, HField);
  else if(displacementField != "")
    deformationfield = readDeformationField(displacementField, Displacement);
  else
    deformationfield = NULL;

  typedef itk::VectorLinearInterpolateImageFunction<DeformationImageType, double> DeformationInterpolateType;
  DeformationInterpolateType::Pointer definterp(NULL);
  if(deformationfield)
  {
    definterp = DeformationInterpolateType::New();
    definterp->SetInputImage(deformationfield);
  } else {
    noWarp = true;
  }

  // Setup new fiber bundle group
  GroupType::Pointer newgroup = GroupType::New();
  newgroup->SetId(0);

  ChildrenListType* children = group->GetChildren(0);

  if(VERBOSE)
    std::cout << "Getting spacing" << std::endl;

  // Get Spacing and offset from group
  double spacing[3];
  if( noWarp )
  {
    newgroup->SetObjectToWorldTransform( group->GetObjectToWorldTransform() ) ;
    newgroup->ComputeObjectToParentTransform() ;
    for(unsigned int i =0; i < 3; i++)
    {
      spacing[i] = (group->GetSpacing())[i];
    }
  }
  else
  {
    spacing[0] = spacing[1] = spacing[2] = 1;
  }
  newgroup->SetSpacing(spacing);

  itk::Vector<double, 3> sooffset;
  for(unsigned int i = 0; i < 3; i++)
    sooffset[i] = (group->GetObjectToParentTransform()->GetOffset())[i];

  if(VERBOSE)
  {
    std::cout << "Group Spacing: " << spacing[0] << ", " << spacing[1] << ", " << spacing[2] << std::endl;
    std::cout << "Group Offset: " << sooffset[0] << ", " << sooffset[1]  << ", " << sooffset[2] << std::endl;
    if (deformationfield)
      std::cout << "deformationfield: '" << deformationfield << "'" << std::endl;
  }

  // Setup tensor file if available
  typedef itk::ImageFileReader<TensorImageType> TensorImageReader;
  typedef itk::TensorLinearInterpolateImageFunction<TensorImageType, double> TensorInterpolateType;
  TensorImageReader::Pointer tensorreader = NULL;
  TensorInterpolateType::Pointer tensorinterp = NULL;

  if(tensorVolume != "")
  {
    tensorreader = TensorImageReader::New();
    tensorinterp = TensorInterpolateType::New();

    tensorreader->SetFileName(tensorVolume);
    try
    {
      tensorreader->Update();
      tensorinterp->SetInputImage(tensorreader->GetOutput());
    }
    catch(itk::ExceptionObject exp)
    {
      std::cerr << exp << std::endl;
      return EXIT_FAILURE;
    }
  }

  if(VERBOSE)
    std::cout << "Starting Loop" << std::endl;

  ChildrenListType::iterator it;
  unsigned int id = 1;

  // Need to allocate an image to write into for creating
  // the fiber label map
  IntImageType::Pointer labelimage;
  if(voxelize != "")
  {
    if(tensorVolume == "")
    {
      std::cerr << "Must specify tensor file to copy image metadata for fiber voxelize." << std::endl;
      return EXIT_FAILURE;
    }
    //tensorreader->GetOutput();
    labelimage = IntImageType::New();
    labelimage->SetSpacing(tensorreader->GetOutput()->GetSpacing());
    labelimage->SetOrigin(tensorreader->GetOutput()->GetOrigin());
    labelimage->SetDirection(tensorreader->GetOutput()->GetDirection());
    labelimage->SetRegions(tensorreader->GetOutput()->GetLargestPossibleRegion());
    labelimage->Allocate();
    labelimage->FillBuffer(0);
  }

  // For each fiber
  for(it = children->begin(); it != children->end(); it++)
  {
    DTIPointListType pointlist = dynamic_cast<DTITubeType*>((*it).GetPointer())->GetPoints();
    DTITubeType::Pointer newtube = DTITubeType::New();
    DTIPointListType newpoints;

    DTIPointListType::iterator pit;

    typedef DeformationInterpolateType::ContinuousIndexType ContinuousIndexType;
    ContinuousIndexType tensor_ci, def_ci ;
    // For each point along the fiber
//std::cout<<"plop"<<std::endl;
    for(pit = pointlist.begin(); pit != pointlist.end(); ++pit)
    {
      typedef DTIPointType::PointType PointType;
//      std::cout<<"plop3"<<std::endl;
      // p is not really a point its a continuous index
      const PointType p = pit->GetPosition();
      DTITubeType::TransformPointer transform = ((*it).GetPointer())->GetObjectToWorldTransform() ;
      const PointType p_world_orig = transform->TransformPoint( p ) ;
//      std::cout<<p_world_orig<<" "<<p<<std::endl;
      itk::Point<double, 3> pt_trans = p_world_orig ;
      if(deformationfield)
      {
        deformationfield->TransformPhysicalPointToContinuousIndex(p_world_orig, def_ci);

        if( !deformationfield->GetLargestPossibleRegion().IsInside( def_ci ) )
        {
          std::cerr << "Fiber is outside deformation field image. Deformation field has to be in the fiber space. Warning: Original position will be used" << std::endl ;
        }
        else
        {
          DeformationPixelType warp(definterp->EvaluateAtContinuousIndex(def_ci).GetDataPointer());
          for( int i = 0 ; i < 3 ; i++ )
          {
            pt_trans[ i ] += warp[ i ] ;
          }
//          deformationfield->TransformContinuousIndexToPhysicalPoint( def_ci , pt_trans ) ;
//          std::cout<<p << " "<< p_world_orig<<" "<<pt_trans<<std::endl;
        }
      }
//            std::cout<<"plop6"<<std::endl;

      if(voxelize != "")
      {
//        std::cout<<p << " "<< p_world_orig<<" "<<pt_trans<<std::endl;
        ContinuousIndexType cind;
        itk::Index<3> ind;
        labelimage->TransformPhysicalPointToContinuousIndex(pt_trans, cind);
        ind[0] = static_cast<long int>(vnl_math_rnd_halfinttoeven(cind[0]));
        ind[1] = static_cast<long int>(vnl_math_rnd_halfinttoeven(cind[1]));
        ind[2] = static_cast<long int>(vnl_math_rnd_halfinttoeven(cind[2]));

        if(!labelimage->GetLargestPossibleRegion().IsInside(ind))
        {
          std::cerr << "Error index: " << ind << " not in image"  << std::endl;
          std::cout << "Ignoring" << std::endl;
          //return EXIT_FAILURE;
	}
        if(voxelizeCountFibers)
        {
          labelimage->SetPixel(ind, labelimage->GetPixel(ind) + 1);
	}
        else
        {
          labelimage->SetPixel(ind, voxelLabel);
	}
      }

      DTIPointType newpoint;
      if(noDataChange==true)
	newpoint = *pit;
      // Should not have to do this
      if(noWarp)
      {
//        std::cout<<"no warp"<<std::endl;
	newpoint.SetPosition(p);
      }
      else
      {
	//set the point to world coordinate system and set the spacing to 1
//        std::cout<<"warp"<<std::endl;
	newpoint.SetPosition(pt_trans);
      }

      //newpoint.SetRadius(.4);
      //newpoint.SetRed(0.0);
      //newpoint.SetGreen(1.0);
      //newpoint.SetBlue(0.0);

      // Attribute tensor data if provided
      if(tensorVolume != "" && fiberOutput != "" && !noDataChange)
      {
	tensorreader->GetOutput()->TransformPhysicalPointToContinuousIndex(pt_trans, tensor_ci);
	itk::DiffusionTensor3D<double> tensor(tensorinterp->EvaluateAtContinuousIndex(tensor_ci).GetDataPointer());

	// TODO: Change SpatialObject interface to accept DiffusionTensor3D
	float sotensor[6];
	for(unsigned int i = 0; i < 6; ++i)
	  sotensor[i] = tensor[i];

	typedef itk::DiffusionTensor3D<double>::EigenValuesArrayType EigenValuesType;
	EigenValuesType eigenvalues;
	tensor.ComputeEigenValues(eigenvalues);

	newpoint.SetRadius(0.5);
	newpoint.SetTensorMatrix(sotensor);
	newpoint.AddField(itk::DTITubeSpatialObjectPoint<3>::FA, tensor.GetFractionalAnisotropy());
	newpoint.AddField("md", tensor.GetTrace()/3);
	newpoint.AddField("fro", sqrt(tensor[0]*tensor[0] +
				      2*tensor[1]*tensor[1] +
				      2*tensor[2]*tensor[2] +
				      tensor[3]*tensor[3] +
				      2*tensor[4]*tensor[4] +
				      tensor[5]*tensor[5]));
	newpoint.AddField("l1", eigenvalues[2]);
	newpoint.AddField("l2", eigenvalues[1]);
	newpoint.AddField("l3", eigenvalues[0]);
      }

      newpoints.push_back(newpoint);
    }
    newtube->SetSpacing(spacing);
    newtube->SetId(id++);
    newtube->SetPoints(newpoints);
    newgroup->AddSpatialObject(newtube);
  }
//  std::cout<<"plop2"<<std::endl;

  if(VERBOSE)
    std::cout << "Ending Loop" << std::endl;

  if(VERBOSE)
    std::cout << "Output: " << fiberOutput << std::endl;

  if(fiberOutput != "")
    writeFiberFile(fiberOutput, newgroup);

  if(voxelize != "")
  {
    typedef itk::ImageFileWriter<IntImageType> LabelWriter;
    LabelWriter::Pointer writer = LabelWriter::New();
    writer->SetInput(labelimage);
    writer->SetFileName(voxelize);
    writer->UseCompressionOn();
    try
    {
      writer->Update();
    }
    catch(itk::ExceptionObject & e)
    {
      std::cerr << e.what() << std::endl;
      return EXIT_FAILURE;
    }
  }

  delete children;
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include "cmm_internal_listener.h"
#include "debug.h"

#define INTERNAL_LISTEN_PORT 42424

ListenerThread::ListenerThread(CMMSocketImpl *sk_)
    : sk(sk_)
{
    struct sockaddr_in bind_addr;
    memset(&bind_addr, 0, sizeof(bind_addr));
    bind_addr.sin_addr.s_addr = INADDR_ANY;
    bind_addr.sin_port = htons(INTERNAL_LISTEN_PORT);

    listener_sock = socket(PF_INET, SOCK_STREAM, 0);
    if (listener_sock < 0) {
        throw -1;
    }

    int on = 1;
    int rc = setsockopt(listener_sock, SOL_SOCKET, SO_REUSEADDR,
                        (char *) &on, sizeof(on));
    if (rc < 0) {
        dbgprintf("Cannot reuse socket address");
    }

    rc = bind(listener_sock,
              (struct sockaddr *)&bind_addr, sizeof(bind_addr));
    if (rc < 0) {
        close(listener_sock);
        throw rc;
    }
    socklen_t addrlen = sizeof(bind_addr);
    rc = getsockname(listener_sock,
                     (struct sockaddr *)&bind_addr, &addrlen);
    if (rc < 0) {
        perror("getsockname");
        close(listener_sock);
        throw rc;
    }
    listen_port = bind_addr.sin_port;
    rc = listen(listener_sock, 5);
    if (rc < 0) {
        close(listener_sock);
        throw rc;
    }
    dbgprintf("Internal socket listener listening up on port %d\n",
              ntohs(listen_port));
}

ListenerThread::~ListenerThread()
{
    close(listener_sock);
}

in_port_t
ListenerThread::port() const
{
    return listen_port;
}

void
ListenerThread::Run()
{
    while (1) {
        fd_set readfds;
        FD_ZERO(&readfds);
        FD_SET(listener_sock, &readfds);
        int rc = select(listener_sock + 1, &readfds, NULL, NULL, NULL);

        struct sockaddr_in remote_addr;
        socklen_t addrlen = sizeof(remote_addr);
        int sock = accept(listener_sock,
                          (struct sockaddr *)&remote_addr, &addrlen);
        if (sock < 0) {
	    perror("accept");
            throw std::runtime_error("Socket error");
        }

        struct sockaddr_in local_addr;
        rc = getsockname(sock,
                         (struct sockaddr *)&local_addr, &addrlen);
        if (rc < 0) {
            perror("getsockname");
            close(sock);
	    close(listener_sock);
            throw std::runtime_error("Socket error");
        }

        try {
            sk->add_connection(sock,
                               local_addr.sin_addr, remote_addr.sin_addr);
        } catch (std::runtime_error& e) {
            dbgprintf("Failed to add connection: %s\n", e.what());
        }
    }
}
<commit_msg>wow, somehow I got away without checking the return code of select in the internal listener thread.  whoops!  fixed that.<commit_after>#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include "cmm_internal_listener.h"
#include "debug.h"

#define INTERNAL_LISTEN_PORT 42424

ListenerThread::ListenerThread(CMMSocketImpl *sk_)
    : sk(sk_)
{
    struct sockaddr_in bind_addr;
    memset(&bind_addr, 0, sizeof(bind_addr));
    bind_addr.sin_addr.s_addr = INADDR_ANY;
    bind_addr.sin_port = htons(INTERNAL_LISTEN_PORT);

    listener_sock = socket(PF_INET, SOCK_STREAM, 0);
    if (listener_sock < 0) {
        throw -1;
    }

    int on = 1;
    int rc = setsockopt(listener_sock, SOL_SOCKET, SO_REUSEADDR,
                        (char *) &on, sizeof(on));
    if (rc < 0) {
        dbgprintf("Cannot reuse socket address");
    }

    rc = bind(listener_sock,
              (struct sockaddr *)&bind_addr, sizeof(bind_addr));
    if (rc < 0) {
        close(listener_sock);
        throw rc;
    }
    socklen_t addrlen = sizeof(bind_addr);
    rc = getsockname(listener_sock,
                     (struct sockaddr *)&bind_addr, &addrlen);
    if (rc < 0) {
        perror("getsockname");
        close(listener_sock);
        throw rc;
    }
    listen_port = bind_addr.sin_port;
    rc = listen(listener_sock, 5);
    if (rc < 0) {
        close(listener_sock);
        throw rc;
    }
    dbgprintf("Internal socket listener listening up on port %d\n",
              ntohs(listen_port));
}

ListenerThread::~ListenerThread()
{
    close(listener_sock);
}

in_port_t
ListenerThread::port() const
{
    return listen_port;
}

void
ListenerThread::Run()
{
    while (1) {
        fd_set readfds;
        FD_ZERO(&readfds);
        FD_SET(listener_sock, &readfds);
        int rc = select(listener_sock + 1, &readfds, NULL, NULL, NULL);
	if (rc < 0) {
	    if (errno == EINTR) {
		continue;
	    } else {
		return;
	    }
	}

        struct sockaddr_in remote_addr;
        socklen_t addrlen = sizeof(remote_addr);
        int sock = accept(listener_sock,
                          (struct sockaddr *)&remote_addr, &addrlen);
        if (sock < 0) {
	    perror("accept");
            throw std::runtime_error("Socket error");
        }

        struct sockaddr_in local_addr;
        rc = getsockname(sock,
                         (struct sockaddr *)&local_addr, &addrlen);
        if (rc < 0) {
            perror("getsockname");
            close(sock);
	    close(listener_sock);
            throw std::runtime_error("Socket error");
        }

        try {
            sk->add_connection(sock,
                               local_addr.sin_addr, remote_addr.sin_addr);
        } catch (std::runtime_error& e) {
            dbgprintf("Failed to add connection: %s\n", e.what());
        }
    }
}
<|endoftext|>


<commit_before>// HLine.cpp
// Copyright (c) 2009, Dan Heeks
// This program is released under the BSD license. See the file COPYING for details.
#include "stdafx.h"

#include "HLine.h"
#include "HILine.h"
#include "HCircle.h"
#include "HArc.h"
#include "../interface/Tool.h"
#include "../interface/PropertyDouble.h"
#include "../interface/PropertyLength.h"
#include "../interface/PropertyVertex.h"
#include "../tinyxml/tinyxml.h"
#include "Gripper.h"

HLine::HLine(const HLine &line){
	operator=(line);
}

HLine::HLine(const gp_Pnt &a, const gp_Pnt &b, const HeeksColor* col){
	A = a;
	B = b;
	color = *col;
}

HLine::~HLine(){
}

const HLine& HLine::operator=(const HLine &b){
	EndedObject::operator=(b);
	color = b.color;
	return *this;
}
HLine* line_for_tool = NULL;

class SetLineHorizontal:public Tool{
public:
	void Run(){
		line_for_tool->SetAbsoluteAngleConstraint(AbsoluteAngleHorizontal);
		wxGetApp().Repaint();
	}
	const wxChar* GetTitle(){return _T("Toggle Horizontal");}
	wxString BitmapPath(){return _T("new");}
	const wxChar* GetToolTip(){return _("Set this line to be horizontal");}
};
static SetLineHorizontal horizontal_line_toggle;

class SetLineVertical:public Tool{
public:
	void Run(){
		line_for_tool->SetAbsoluteAngleConstraint(AbsoluteAngleVertical);
		wxGetApp().Repaint();
	}
	const wxChar* GetTitle(){return _T("Toggle Vertical");}
	wxString BitmapPath(){return _T("new");}
	const wxChar* GetToolTip(){return _("Set this line to be vertical");}
};
static SetLineVertical vertical_line_toggle;

void HLine::GetTools(std::list<Tool*>* t_list, const wxPoint* p)
{
	line_for_tool = this;
	t_list->push_back(&horizontal_line_toggle);
	t_list->push_back(&vertical_line_toggle);
}

void HLine::glCommands(bool select, bool marked, bool no_color){
	if(!no_color){
		wxGetApp().glColorEnsuringContrast(color);
	}
	GLfloat save_depth_range[2];
	if(marked){
		glGetFloatv(GL_DEPTH_RANGE, save_depth_range);
		glDepthRange(0, 0);
		glLineWidth(2);
	}
	glBegin(GL_LINES);
	glVertex3d(A.X(), A.Y(), A.Z());
	glVertex3d(B.X(), B.Y(), B.Z());
	glEnd();
	if(marked){
		glLineWidth(1);
		glDepthRange(save_depth_range[0], save_depth_range[1]);
	}
	gp_Pnt mid_point = A.XYZ() + (B.XYZ() - A.XYZ())/2;
	gp_Dir dir = B.XYZ() - mid_point.XYZ();
	gp_Ax1 ax(mid_point,dir);
	//gp_Dir up(0,0,1);
	//ax.Rotate(gp_Ax1(mid_point,up),Pi/2);
	ConstrainedObject::glCommands(color,ax);
}

void HLine::Draw(wxDC& dc)
{
	wxGetApp().PlotSetColor(color);
	double s[3], e[3];
	extract(A, s);
	extract(B, e);
	wxGetApp().PlotLine(s, e);
}

HeeksObj *HLine::MakeACopy(void)const{
	HLine *new_object = new HLine(*this);
	return new_object;
}

void HLine::GetBox(CBox &box){
	box.Insert(A.X(), A.Y(), A.Z());
	box.Insert(B.X(), B.Y(), B.Z());
}

void HLine::GetGripperPositions(std::list<double> *list, bool just_for_endof){
	list->push_back(GripperTypeStretch);
	list->push_back(A.X());
	list->push_back(A.Y());
	list->push_back(A.Z());
	list->push_back(GripperTypeStretch);
	list->push_back(B.X());
	list->push_back(B.Y());
	list->push_back(B.Z());
}

static void on_set_start(const double *vt, HeeksObj* object){
	((HLine*)object)->A = make_point(vt);
	wxGetApp().Repaint();
}

static void on_set_end(const double *vt, HeeksObj* object){
	((HLine*)object)->B = make_point(vt);
	wxGetApp().Repaint();
}

void HLine::GetProperties(std::list<Property *> *list){
	double a[3], b[3];
	extract(A, a);
	extract(B, b);
	list->push_back(new PropertyVertex(_("start"), a, this, on_set_start));
	list->push_back(new PropertyVertex(_("end"), b, this, on_set_end));
	double length = A.Distance(B);
	list->push_back(new PropertyLength(_("Length"), length, NULL));

	HeeksObj::GetProperties(list);
}

bool HLine::FindNearPoint(const double* ray_start, const double* ray_direction, double *point){
	gp_Lin ray(make_point(ray_start), make_vector(ray_direction));
	gp_Pnt p1, p2;
	ClosestPointsOnLines(GetLine(), ray, p1, p2);

	if(!Intersects(p1))
		return false;

	extract(p1, point);
	return true;
}

bool HLine::FindPossTangentPoint(const double* ray_start, const double* ray_direction, double *point){
	// any point on this line is a possible tangent point
	return FindNearPoint(ray_start, ray_direction, point);
}

gp_Lin HLine::GetLine()const{
	gp_Vec v(A, B);
	return gp_Lin(A, v);
}

int HLine::Intersects(const HeeksObj *object, std::list< double > *rl)const{
	int numi = 0;

	switch(object->GetType())
	{
	case LineType:
		{
			// The OpenCascase libraries throw an exception when one tries to
			// create a gp_Lin() object using a vector that doesn't point
			// anywhere.  If this is a zero-length line then we're in
			// trouble.  Don't both with it.
			if ((A.X() == B.X()) &&
			    (A.Y() == B.Y()) &&
			    (A.Z() == B.Z())) break;

			gp_Pnt pnt;
			if(intersect(GetLine(), ((HLine*)object)->GetLine(), pnt))
			{
				if(Intersects(pnt) && ((HLine*)object)->Intersects(pnt)){
					if(rl)add_pnt_to_doubles(pnt, *rl);
					numi++;
				}
			}
		}
		break;

	case ILineType:
		{
			gp_Pnt pnt;
			if(intersect(GetLine(), ((HILine*)object)->GetLine(), pnt))
			{
				if(Intersects(pnt)){
					if(rl)add_pnt_to_doubles(pnt, *rl);
					numi++;
				}
			}
		}
		break;

	case ArcType:
		{
			std::list<gp_Pnt> plist;
			intersect(GetLine(), ((HArc*)object)->m_circle, plist);
			for(std::list<gp_Pnt>::iterator It = plist.begin(); It != plist.end(); It++)
			{
				gp_Pnt& pnt = *It;
				if(Intersects(pnt) && ((HArc*)object)->Intersects(pnt))
				{
					if(rl)add_pnt_to_doubles(pnt, *rl);
					numi++;
				}
			}
		}
		break;

	case CircleType:
		{
			std::list<gp_Pnt> plist;
			intersect(GetLine(), ((HCircle*)object)->m_circle, plist);
			for(std::list<gp_Pnt>::iterator It = plist.begin(); It != plist.end(); It++)
			{
				gp_Pnt& pnt = *It;
				if(Intersects(pnt))
				{
					if(rl)add_pnt_to_doubles(pnt, *rl);
					numi++;
				}
			}
		}
		break;
	}

	return numi;
}

bool HLine::Intersects(const gp_Pnt &pnt)const
{
	gp_Lin this_line = GetLine();
	if(!intersect(pnt, this_line))return false;

	// check it lies between A and B
	gp_Vec v = this_line.Direction();
	double dpA = gp_Vec(A.XYZ()) * v;
	double dpB = gp_Vec(B.XYZ()) * v;
	double dp = gp_Vec(pnt.XYZ()) * v;
	return dp >= dpA - wxGetApp().m_geom_tol && dp <= dpB + wxGetApp().m_geom_tol;
}

void HLine::GetSegments(void(*callbackfunc)(const double *p), double pixels_per_mm, bool want_start_point)const{
	if(want_start_point)
	{
		double p[3];
		extract(A, p);
		(*callbackfunc)(p);
	}

	double p[3];
	extract(B, p);
	(*callbackfunc)(p);
}

gp_Vec HLine::GetSegmentVector(double fraction)
{
	gp_Vec line_vector(A, B);
	if(line_vector.Magnitude() < 0.000000001)return gp_Vec(0, 0, 0);
	return gp_Vec(A, B).Normalized();
}

void HLine::WriteXML(TiXmlNode *root)
{
	TiXmlElement * element;
	element = new TiXmlElement( "Line" );
	root->LinkEndChild( element );
	element->SetAttribute("col", color.COLORREF_color());
	element->SetDoubleAttribute("sx", A.X());
	element->SetDoubleAttribute("sy", A.Y());
	element->SetDoubleAttribute("sz", A.Z());
	element->SetDoubleAttribute("ex", B.X());
	element->SetDoubleAttribute("ey", B.Y());
	element->SetDoubleAttribute("ez", B.Z());
	WriteBaseXML(element);
}

// static member function
HeeksObj* HLine::ReadFromXMLElement(TiXmlElement* pElem)
{
	gp_Pnt p0, p1;
	HeeksColor c;

	// get the attributes
	for(TiXmlAttribute* a = pElem->FirstAttribute(); a; a = a->Next())
	{
		std::string name(a->Name());
		if(name == "col"){c = HeeksColor(a->IntValue());}
		else if(name == "sx"){p0.SetX(a->DoubleValue());}
		else if(name == "sy"){p0.SetY(a->DoubleValue());}
		else if(name == "sz"){p0.SetZ(a->DoubleValue());}
		else if(name == "ex"){p1.SetX(a->DoubleValue());}
		else if(name == "ey"){p1.SetY(a->DoubleValue());}
		else if(name == "ez"){p1.SetZ(a->DoubleValue());}
	}

	HLine* new_object = new HLine(p0, p1, &c);
	new_object->ReadBaseXML(pElem);

	return new_object;
}

void HLine::Reverse()
{
	gp_Pnt temp = A;
	A = B;
	B = temp;
}

<commit_msg>Fixed Issue 162:  	 Drawing regular shape (rectangle) causes crash gp_Dir doesn't like having no length. We don't seem to handle Open CASCADE's errors too well. Anyway, this change stops gp_Dir being constructed with no length, in this case.<commit_after>// HLine.cpp
// Copyright (c) 2009, Dan Heeks
// This program is released under the BSD license. See the file COPYING for details.
#include "stdafx.h"

#include "HLine.h"
#include "HILine.h"
#include "HCircle.h"
#include "HArc.h"
#include "../interface/Tool.h"
#include "../interface/PropertyDouble.h"
#include "../interface/PropertyLength.h"
#include "../interface/PropertyVertex.h"
#include "../tinyxml/tinyxml.h"
#include "Gripper.h"

HLine::HLine(const HLine &line){
	operator=(line);
}

HLine::HLine(const gp_Pnt &a, const gp_Pnt &b, const HeeksColor* col){
	A = a;
	B = b;
	color = *col;
}

HLine::~HLine(){
}

const HLine& HLine::operator=(const HLine &b){
	EndedObject::operator=(b);
	color = b.color;
	return *this;
}
HLine* line_for_tool = NULL;

class SetLineHorizontal:public Tool{
public:
	void Run(){
		line_for_tool->SetAbsoluteAngleConstraint(AbsoluteAngleHorizontal);
		wxGetApp().Repaint();
	}
	const wxChar* GetTitle(){return _T("Toggle Horizontal");}
	wxString BitmapPath(){return _T("new");}
	const wxChar* GetToolTip(){return _("Set this line to be horizontal");}
};
static SetLineHorizontal horizontal_line_toggle;

class SetLineVertical:public Tool{
public:
	void Run(){
		line_for_tool->SetAbsoluteAngleConstraint(AbsoluteAngleVertical);
		wxGetApp().Repaint();
	}
	const wxChar* GetTitle(){return _T("Toggle Vertical");}
	wxString BitmapPath(){return _T("new");}
	const wxChar* GetToolTip(){return _("Set this line to be vertical");}
};
static SetLineVertical vertical_line_toggle;

void HLine::GetTools(std::list<Tool*>* t_list, const wxPoint* p)
{
	line_for_tool = this;
	t_list->push_back(&horizontal_line_toggle);
	t_list->push_back(&vertical_line_toggle);
}

void HLine::glCommands(bool select, bool marked, bool no_color){
	if(!no_color){
		wxGetApp().glColorEnsuringContrast(color);
	}
	GLfloat save_depth_range[2];
	if(marked){
		glGetFloatv(GL_DEPTH_RANGE, save_depth_range);
		glDepthRange(0, 0);
		glLineWidth(2);
	}
	glBegin(GL_LINES);
	glVertex3d(A.X(), A.Y(), A.Z());
	glVertex3d(B.X(), B.Y(), B.Z());
	glEnd();
	if(marked){
		glLineWidth(1);
		glDepthRange(save_depth_range[0], save_depth_range[1]);
	}

	if(!A.IsEqual(B, wxGetApp().m_geom_tol))
	{
		gp_Pnt mid_point = A.XYZ() + (B.XYZ() - A.XYZ())/2;
		gp_Dir dir = B.XYZ() - mid_point.XYZ();
		gp_Ax1 ax(mid_point,dir);
		//gp_Dir up(0,0,1);
		//ax.Rotate(gp_Ax1(mid_point,up),Pi/2);
		ConstrainedObject::glCommands(color,ax);
	}
}

void HLine::Draw(wxDC& dc)
{
	wxGetApp().PlotSetColor(color);
	double s[3], e[3];
	extract(A, s);
	extract(B, e);
	wxGetApp().PlotLine(s, e);
}

HeeksObj *HLine::MakeACopy(void)const{
	HLine *new_object = new HLine(*this);
	return new_object;
}

void HLine::GetBox(CBox &box){
	box.Insert(A.X(), A.Y(), A.Z());
	box.Insert(B.X(), B.Y(), B.Z());
}

void HLine::GetGripperPositions(std::list<double> *list, bool just_for_endof){
	list->push_back(GripperTypeStretch);
	list->push_back(A.X());
	list->push_back(A.Y());
	list->push_back(A.Z());
	list->push_back(GripperTypeStretch);
	list->push_back(B.X());
	list->push_back(B.Y());
	list->push_back(B.Z());
}

static void on_set_start(const double *vt, HeeksObj* object){
	((HLine*)object)->A = make_point(vt);
	wxGetApp().Repaint();
}

static void on_set_end(const double *vt, HeeksObj* object){
	((HLine*)object)->B = make_point(vt);
	wxGetApp().Repaint();
}

void HLine::GetProperties(std::list<Property *> *list){
	double a[3], b[3];
	extract(A, a);
	extract(B, b);
	list->push_back(new PropertyVertex(_("start"), a, this, on_set_start));
	list->push_back(new PropertyVertex(_("end"), b, this, on_set_end));
	double length = A.Distance(B);
	list->push_back(new PropertyLength(_("Length"), length, NULL));

	HeeksObj::GetProperties(list);
}

bool HLine::FindNearPoint(const double* ray_start, const double* ray_direction, double *point){
	gp_Lin ray(make_point(ray_start), make_vector(ray_direction));
	gp_Pnt p1, p2;
	ClosestPointsOnLines(GetLine(), ray, p1, p2);

	if(!Intersects(p1))
		return false;

	extract(p1, point);
	return true;
}

bool HLine::FindPossTangentPoint(const double* ray_start, const double* ray_direction, double *point){
	// any point on this line is a possible tangent point
	return FindNearPoint(ray_start, ray_direction, point);
}

gp_Lin HLine::GetLine()const{
	gp_Vec v(A, B);
	return gp_Lin(A, v);
}

int HLine::Intersects(const HeeksObj *object, std::list< double > *rl)const{
	int numi = 0;

	switch(object->GetType())
	{
	case LineType:
		{
			// The OpenCascase libraries throw an exception when one tries to
			// create a gp_Lin() object using a vector that doesn't point
			// anywhere.  If this is a zero-length line then we're in
			// trouble.  Don't both with it.
			if ((A.X() == B.X()) &&
			    (A.Y() == B.Y()) &&
			    (A.Z() == B.Z())) break;

			gp_Pnt pnt;
			if(intersect(GetLine(), ((HLine*)object)->GetLine(), pnt))
			{
				if(Intersects(pnt) && ((HLine*)object)->Intersects(pnt)){
					if(rl)add_pnt_to_doubles(pnt, *rl);
					numi++;
				}
			}
		}
		break;

	case ILineType:
		{
			gp_Pnt pnt;
			if(intersect(GetLine(), ((HILine*)object)->GetLine(), pnt))
			{
				if(Intersects(pnt)){
					if(rl)add_pnt_to_doubles(pnt, *rl);
					numi++;
				}
			}
		}
		break;

	case ArcType:
		{
			std::list<gp_Pnt> plist;
			intersect(GetLine(), ((HArc*)object)->m_circle, plist);
			for(std::list<gp_Pnt>::iterator It = plist.begin(); It != plist.end(); It++)
			{
				gp_Pnt& pnt = *It;
				if(Intersects(pnt) && ((HArc*)object)->Intersects(pnt))
				{
					if(rl)add_pnt_to_doubles(pnt, *rl);
					numi++;
				}
			}
		}
		break;

	case CircleType:
		{
			std::list<gp_Pnt> plist;
			intersect(GetLine(), ((HCircle*)object)->m_circle, plist);
			for(std::list<gp_Pnt>::iterator It = plist.begin(); It != plist.end(); It++)
			{
				gp_Pnt& pnt = *It;
				if(Intersects(pnt))
				{
					if(rl)add_pnt_to_doubles(pnt, *rl);
					numi++;
				}
			}
		}
		break;
	}

	return numi;
}

bool HLine::Intersects(const gp_Pnt &pnt)const
{
	gp_Lin this_line = GetLine();
	if(!intersect(pnt, this_line))return false;

	// check it lies between A and B
	gp_Vec v = this_line.Direction();
	double dpA = gp_Vec(A.XYZ()) * v;
	double dpB = gp_Vec(B.XYZ()) * v;
	double dp = gp_Vec(pnt.XYZ()) * v;
	return dp >= dpA - wxGetApp().m_geom_tol && dp <= dpB + wxGetApp().m_geom_tol;
}

void HLine::GetSegments(void(*callbackfunc)(const double *p), double pixels_per_mm, bool want_start_point)const{
	if(want_start_point)
	{
		double p[3];
		extract(A, p);
		(*callbackfunc)(p);
	}

	double p[3];
	extract(B, p);
	(*callbackfunc)(p);
}

gp_Vec HLine::GetSegmentVector(double fraction)
{
	gp_Vec line_vector(A, B);
	if(line_vector.Magnitude() < 0.000000001)return gp_Vec(0, 0, 0);
	return gp_Vec(A, B).Normalized();
}

void HLine::WriteXML(TiXmlNode *root)
{
	TiXmlElement * element;
	element = new TiXmlElement( "Line" );
	root->LinkEndChild( element );
	element->SetAttribute("col", color.COLORREF_color());
	element->SetDoubleAttribute("sx", A.X());
	element->SetDoubleAttribute("sy", A.Y());
	element->SetDoubleAttribute("sz", A.Z());
	element->SetDoubleAttribute("ex", B.X());
	element->SetDoubleAttribute("ey", B.Y());
	element->SetDoubleAttribute("ez", B.Z());
	WriteBaseXML(element);
}

// static member function
HeeksObj* HLine::ReadFromXMLElement(TiXmlElement* pElem)
{
	gp_Pnt p0, p1;
	HeeksColor c;

	// get the attributes
	for(TiXmlAttribute* a = pElem->FirstAttribute(); a; a = a->Next())
	{
		std::string name(a->Name());
		if(name == "col"){c = HeeksColor(a->IntValue());}
		else if(name == "sx"){p0.SetX(a->DoubleValue());}
		else if(name == "sy"){p0.SetY(a->DoubleValue());}
		else if(name == "sz"){p0.SetZ(a->DoubleValue());}
		else if(name == "ex"){p1.SetX(a->DoubleValue());}
		else if(name == "ey"){p1.SetY(a->DoubleValue());}
		else if(name == "ez"){p1.SetZ(a->DoubleValue());}
	}

	HLine* new_object = new HLine(p0, p1, &c);
	new_object->ReadBaseXML(pElem);

	return new_object;
}

void HLine::Reverse()
{
	gp_Pnt temp = A;
	A = B;
	B = temp;
}

<|endoftext|>


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

#include <cmake.h>
#include <algorithm>
// If <iostream> is included, put it after <stdio.h>, because it includes
// <stdio.h>, and therefore would ignore the _WITH_GETLINE.
#ifdef FREEBSD
#define _WITH_GETLINE
#endif
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <Context.h>
#include <JSON.h>
#include <Hooks.h>
#include <text.h>
#include <util.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
Hooks::Hooks ()
: _enabled (true)
, _debug (0)
{
}

////////////////////////////////////////////////////////////////////////////////
Hooks::~Hooks ()
{
}

////////////////////////////////////////////////////////////////////////////////
void Hooks::initialize ()
{
  _debug = context.config.getInteger ("debug.hooks");

  // Scan <rc.data.location>/hooks
  Directory d (context.config.get ("data.location"));
  d += "hooks";
  if (d.is_directory () &&
      d.readable ())
  {
    _scripts = d.list ();
    std::sort (_scripts.begin (), _scripts.end ());

    if (_debug >= 1)
    {
      std::vector <std::string>::iterator i;
      for (i = _scripts.begin (); i != _scripts.end (); ++i)
        context.debug ("Found hook script " + *i);
    }
  }
  else if (_debug >= 1)
    context.debug ("Hook directory not readable: " + d._data);

  _enabled = context.config.getBoolean ("hooks");
}

////////////////////////////////////////////////////////////////////////////////
bool Hooks::enable (bool value)
{
  bool old_value = _enabled;
  _enabled = value;
  return old_value;
}

////////////////////////////////////////////////////////////////////////////////
// The on-launch event is triggered once, after initialization, before any
// processing occurs, i.e first
//
// Input:
// - none
//
// Output:
// - all emitted JSON lines are added/modified as tasks, if the exit code is
//   zero, otherwise ignored.
// - minimal new task:  {"description":"Buy milk"}
// - to modify a task include complete JSON
// - all emitted non-JSON lines are considered feedback messages if the exit
//   code is zero, otherwise they are considered errors.
//
void Hooks::onLaunch ()
{
  if (! _enabled)
    return;

  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-launch");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    if (_debug >= 1)
      context.debug ("Hooks: Calling " + *i);

    std::string output;
    std::vector <std::string> args;
    int status = execute (*i, args, "", output);

    if (_debug >= 2)
      context.debug (format ("Hooks: Completed with status {1}", status));

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (isJSON (*line))
        {
          if (_debug >= 2)
            context.debug ("Hook output: " + *line);

          // Only 'add' is possible.
          Task newTask (*line);
          context.tdb2.add (newTask);
        }
        else
          context.header (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        if (! isJSON (*line))
          context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// The on-exit event is triggered once, after all processing is complete, i.e.
// last
//
// Input:
// - read-only line of JSON for each task added/modified
//
// Output:
// - any emitted JSON is ignored
// - all emitted non-JSON lines are considered feedback messages if the exit
//   code is zero, otherwise they are considered errors.
//
void Hooks::onExit ()
{
  if (! _enabled)
    return;

  context.timer_hooks.start ();

  std::vector <Task> changes;
  context.tdb2.get_changes (changes);

  std::string input = "";
  std::vector <Task>::const_iterator t;
  for (t = changes.begin (); t != changes.end (); ++t)
  {
    std::string json = t->composeJSON ();
    if (_debug >= 2)
      context.debug ("Hook input: " + json);

    input += json + "\n";
  }

  std::vector <std::string> matchingScripts = scripts ("on-exit");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    if (_debug >= 1)
      context.debug ("Hooks: Calling " + *i);

    std::string output;
    std::vector <std::string> args;
    int status = execute (*i, args, input, output);

    if (_debug >= 2)
      context.debug (format ("Hooks: Completed with status {1}", status));

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    for (line = lines.begin (); line != lines.end (); ++line)
    {
      if (_debug >= 2)
        context.debug ("Hook output: " + *line);

      if (! isJSON (*line))
      {
        if (status == 0)
          context.footnote (*line);
        else
          context.error (*line);
      }
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// The on-add event is triggered separately for each task added
//
// Input:
// - line of JSON for the task added
//
// Output:
// - all emitted JSON lines are added/modified as tasks, if the exit code is
//   zero, otherwise ignored.
// - minimal new task:  {"description":"Buy milk"}
// - to modify a task include complete JSON
// - all emitted non-JSON lines are considered feedback messages if the exit
//   code is zero, otherwise they are considered errors.
//
void Hooks::onAdd (std::vector <Task>& changes)
{
  if (! _enabled)
    return;

  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-add");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    if (_debug >= 1)
      context.debug ("Hooks: Calling " + *i);

    std::string input = changes.at(0).composeJSON ();
    if (_debug >= 2)
      context.debug ("Hook input: " + input);

    input += "\n";
    std::string output;
    std::vector <std::string> args;
    int status = execute (*i, args, input, output);

    if (_debug >= 2)
      context.debug (format ("Hooks: Completed with status {1}", status));

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      changes.clear ();
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (_debug >= 2)
          context.debug ("Hook output: " + *line);

        if (isJSON (*line))
          changes.push_back (Task (*line));
        else
          context.footnote (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        if (! isJSON (*line))
          context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// The on-modify event is triggered separately for each task added or modified
//
// Input:
// - line of JSON for the original task
// - line of JSON for the modified task, the diff being the modification
//
// Output:
// - all emitted JSON lines are added/modified as tasks, if the exit code is
//   zero, otherwise ignored.
// - minimal new task:  {"description":"Buy milk"}
// - to modify a task include complete JSON
// - all emitted non-JSON lines are considered feedback messages if the exit
//   code is zero, otherwise they are considered errors.
//
void Hooks::onModify (const Task& before, std::vector <Task>& changes)
{
  if (! _enabled)
    return;

  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-modify");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    if (_debug >= 1)
      context.debug ("Hooks: Calling " + *i);

    std::string beforeJSON = before.composeJSON ();
    std::string afterJSON = changes[0].composeJSON ();
    if (_debug >= 2)
    {
      context.debug ("Hook input: " + beforeJSON);
      context.debug ("Hook input: " + afterJSON);
    }

    std::string input = beforeJSON
                      + "\n"
                      + afterJSON
                      + "\n";
    std::string output;
    std::vector <std::string> args;
    int status = execute (*i, args, input, output);

    if (_debug >= 2)
      context.debug (format ("Hooks: Completed with status {1}", status));

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      changes.clear ();
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (_debug >= 2)
          context.debug ("Hook output: " + *line);

        if (isJSON (*line))
          changes.push_back (Task (*line));
        else
          context.footnote (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        if (! isJSON (*line))
          context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> Hooks::list ()
{
  return _scripts;
}

////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> Hooks::scripts (const std::string& event)
{
  std::vector <std::string> matching;
  std::vector <std::string>::iterator i;
  for (i = _scripts.begin (); i != _scripts.end (); ++i)
  {
    if (i->find ("/" + event) != std::string::npos)
    {
      File script (*i);
      if (script.executable ())
        matching.push_back (*i);
    }
  }

  return matching;
}

////////////////////////////////////////////////////////////////////////////////
bool Hooks::isJSON (const std::string& input) const
{
  // Does it even look like JSON?  {...}
  if (input.length () > 2 &&
      input[0] == '{'     &&
      input[input.length () - 1] == '}')
  {
    try
    {
      // The absolute minimum a task needs is:
      bool foundDescription = false;

      // Parse the whole thing.
      json::value* root = json::parse (input);
      if (root->type () == json::j_object)
      {
        json::object* root_obj = (json::object*)root;

        // For each object element...
        json_object_iter i;
        for (i  = root_obj->_data.begin ();
             i != root_obj->_data.end ();
             ++i)
        {
          // If the attribute is a recognized column.
          std::string type = Task::attributes[i->first];
          if (type == "string" && i->first == "description")
            foundDescription = true;
        }
      }
      else
        throw std::string ("Object expected.");

      // It's JSON, but is it a task?
      if (! foundDescription)
        throw std::string ("Missing 'description' attribute, of type 'string'.");

      // Yep, looks like a JSON task.
      return true;
    }

    catch (const std::string& e)
    {
      if (_debug >= 1)
        context.error ("Hook output looks like JSON, but is not a valid task.");

      if (_debug >= 2)
        context.error ("JSON " + e);
    }

    catch (...)
    {
      if (_debug >= 1)
        context.error ("Hook output looks like JSON, but fails to parse.");
    }
  }

  return false;
}

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

#include <cmake.h>
#include <algorithm>
// If <iostream> is included, put it after <stdio.h>, because it includes
// <stdio.h>, and therefore would ignore the _WITH_GETLINE.
#ifdef FREEBSD
#define _WITH_GETLINE
#endif
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <Context.h>
#include <JSON.h>
#include <Hooks.h>
#include <text.h>
#include <util.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
Hooks::Hooks ()
: _enabled (true)
, _debug (0)
{
}

////////////////////////////////////////////////////////////////////////////////
Hooks::~Hooks ()
{
}

////////////////////////////////////////////////////////////////////////////////
void Hooks::initialize ()
{
  _debug = context.config.getInteger ("debug.hooks");

  // Scan <rc.data.location>/hooks
  Directory d (context.config.get ("data.location"));
  d += "hooks";
  if (d.is_directory () &&
      d.readable ())
  {
    _scripts = d.list ();
    std::sort (_scripts.begin (), _scripts.end ());

    if (_debug >= 1)
    {
      std::vector <std::string>::iterator i;
      for (i = _scripts.begin (); i != _scripts.end (); ++i)
        context.debug ("Found hook script " + *i);
    }
  }
  else if (_debug >= 1)
    context.debug ("Hook directory not readable: " + d._data);

  _enabled = context.config.getBoolean ("hooks");
}

////////////////////////////////////////////////////////////////////////////////
bool Hooks::enable (bool value)
{
  bool old_value = _enabled;
  _enabled = value;
  return old_value;
}

////////////////////////////////////////////////////////////////////////////////
// The on-launch event is triggered once, after initialization, before any
// processing occurs, i.e first
//
// Input:
// - none
//
// Output:
// - all emitted JSON lines are added/modified as tasks, if the exit code is
//   zero, otherwise ignored.
// - minimal new task:  {"description":"Buy milk"}
// - to modify a task include complete JSON
// - all emitted non-JSON lines are considered feedback messages if the exit
//   code is zero, otherwise they are considered errors.
//
void Hooks::onLaunch ()
{
  if (! _enabled)
    return;

  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-launch");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    if (_debug >= 1)
      context.debug ("Hooks: Calling " + *i);

    std::string output;
    std::vector <std::string> args;
    int status = execute (*i, args, "", output);

    if (_debug >= 2)
      context.debug (format ("Hooks: Completed with status {1}", status));

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (isJSON (*line))
        {
          if (_debug >= 2)
          {
            context.debug ("Hook output:");
            context.debug ("  " + *line);
          }

          // Only 'add' is possible.
          Task newTask (*line);
          context.tdb2.add (newTask);
        }
        else
          context.header (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        if (! isJSON (*line))
          context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// The on-exit event is triggered once, after all processing is complete, i.e.
// last
//
// Input:
// - read-only line of JSON for each task added/modified
//
// Output:
// - any emitted JSON is ignored
// - all emitted non-JSON lines are considered feedback messages if the exit
//   code is zero, otherwise they are considered errors.
//
void Hooks::onExit ()
{
  if (! _enabled)
    return;

  context.timer_hooks.start ();

  std::vector <Task> changes;
  context.tdb2.get_changes (changes);

  std::string input = "";
  std::vector <Task>::const_iterator t;
  for (t = changes.begin (); t != changes.end (); ++t)
  {
    std::string json = t->composeJSON ();
    if (_debug >= 2)
      context.debug ("Hook input: " + json);

    input += json + "\n";
  }

  std::vector <std::string> matchingScripts = scripts ("on-exit");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    if (_debug >= 1)
      context.debug ("Hooks: Calling " + *i);

    std::string output;
    std::vector <std::string> args;
    int status = execute (*i, args, input, output);

    if (_debug >= 2)
      context.debug (format ("Hooks: Completed with status {1}", status));

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (_debug >= 2)
      context.debug ("Hook output:");

    for (line = lines.begin (); line != lines.end (); ++line)
    {
      if (! isJSON (*line))
      {
        if (_debug >= 2)
          context.debug ("  " + *line);

        if (status == 0)
          context.footnote (*line);
        else
          context.error (*line);
      }
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// The on-add event is triggered separately for each task added
//
// Input:
// - line of JSON for the task added
//
// Output:
// - all emitted JSON lines are added/modified as tasks, if the exit code is
//   zero, otherwise ignored.
// - minimal new task:  {"description":"Buy milk"}
// - to modify a task include complete JSON
// - all emitted non-JSON lines are considered feedback messages if the exit
//   code is zero, otherwise they are considered errors.
//
void Hooks::onAdd (std::vector <Task>& changes)
{
  if (! _enabled)
    return;

  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-add");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    if (_debug >= 1)
      context.debug ("Hooks: Calling " + *i);

    std::string input = changes.at(0).composeJSON ();
    if (_debug >= 2)
      context.debug ("Hook input: " + input);

    input += "\n";
    std::string output;
    std::vector <std::string> args;
    int status = execute (*i, args, input, output);

    if (_debug >= 2)
      context.debug (format ("Hooks: Completed with status {1}", status));

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      changes.clear ();

      if (_debug >= 2)
        context.debug ("Hook output:");

      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (_debug >= 2)
          context.debug ("  " + *line);

        if (isJSON (*line))
          changes.push_back (Task (*line));
        else
          context.footnote (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        if (! isJSON (*line))
          context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// The on-modify event is triggered separately for each task added or modified
//
// Input:
// - line of JSON for the original task
// - line of JSON for the modified task, the diff being the modification
//
// Output:
// - all emitted JSON lines are added/modified as tasks, if the exit code is
//   zero, otherwise ignored.
// - minimal new task:  {"description":"Buy milk"}
// - to modify a task include complete JSON
// - all emitted non-JSON lines are considered feedback messages if the exit
//   code is zero, otherwise they are considered errors.
//
void Hooks::onModify (const Task& before, std::vector <Task>& changes)
{
  if (! _enabled)
    return;

  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-modify");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    if (_debug >= 1)
      context.debug ("Hooks: Calling " + *i);

    std::string beforeJSON = before.composeJSON ();
    std::string afterJSON = changes[0].composeJSON ();
    if (_debug >= 2)
    {
      context.debug ("Hook input:");
      context.debug ("  " + beforeJSON);
      context.debug ("  " + afterJSON);
    }

    std::string input = beforeJSON
                      + "\n"
                      + afterJSON
                      + "\n";
    std::string output;
    std::vector <std::string> args;
    int status = execute (*i, args, input, output);

    if (_debug >= 2)
      context.debug (format ("Hooks: Completed with status {1}", status));

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      changes.clear ();

      if (_debug >= 2)
        context.debug ("Hook output:");

      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (_debug >= 2)
          context.debug ("  " + *line);

        if (isJSON (*line))
          changes.push_back (Task (*line));
        else
          context.footnote (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        if (! isJSON (*line))
          context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> Hooks::list ()
{
  return _scripts;
}

////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> Hooks::scripts (const std::string& event)
{
  std::vector <std::string> matching;
  std::vector <std::string>::iterator i;
  for (i = _scripts.begin (); i != _scripts.end (); ++i)
  {
    if (i->find ("/" + event) != std::string::npos)
    {
      File script (*i);
      if (script.executable ())
        matching.push_back (*i);
    }
  }

  return matching;
}

////////////////////////////////////////////////////////////////////////////////
bool Hooks::isJSON (const std::string& input) const
{
  // Does it even look like JSON?  {...}
  if (input.length () > 2 &&
      input[0] == '{'     &&
      input[input.length () - 1] == '}')
  {
    try
    {
      // The absolute minimum a task needs is:
      bool foundDescription = false;

      // Parse the whole thing.
      json::value* root = json::parse (input);
      if (root->type () == json::j_object)
      {
        json::object* root_obj = (json::object*)root;

        // For each object element...
        json_object_iter i;
        for (i  = root_obj->_data.begin ();
             i != root_obj->_data.end ();
             ++i)
        {
          // If the attribute is a recognized column.
          std::string type = Task::attributes[i->first];
          if (type == "string" && i->first == "description")
            foundDescription = true;
        }
      }
      else
        throw std::string ("Object expected.");

      // It's JSON, but is it a task?
      if (! foundDescription)
        throw std::string ("Missing 'description' attribute, of type 'string'.");

      // Yep, looks like a JSON task.
      return true;
    }

    catch (const std::string& e)
    {
      if (_debug >= 1)
        context.error ("Hook output looks like JSON, but is not a valid task.");

      if (_debug >= 2)
        context.error ("JSON " + e);
    }

    catch (...)
    {
      if (_debug >= 1)
        context.error ("Hook output looks like JSON, but fails to parse.");
    }
  }

  return false;
}

////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>#include <iostream>
#include "Input.h"
#include <queue>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
#include <algorithm>

using namespace std;

// void Input::setUser() {
// }

void Input::getInput() {
    strLine.clear();
    cout << "$ ";
    getline (cin, strLine);

    // if the user ONLY entered exit
    if (strLine == "exit") {
        cout << "You have exited shell." << endl;
        exit(0);
    }

    // if # spotted, cuts off # and everything after it
    size_t found = strLine.find('#');
    if (found != string::npos) {
        strLine.erase(strLine.begin() + found, strLine.end());
        if (strLine.size() == 0) {
            // cout << "nothing left" << endl;
        }
    }
}

bool Input::isTest() {
    size_t found = strLine.find('[');
    if (found != string::npos) {
        if ( validTest() ) {
            return true;
        }
        return false;
    }

    // check if test is first word in string or after connector
    if (strLine.find("test ") != string::npos) {
        return true;
    }

    return false;
}

// handle error when user puts something like "] [" wtf
bool Input::validTest() {
    size_t cntrOpen  = std::count(strLine.begin(), strLine.end(), '[');
    size_t cntrClose = std::count(strLine.begin(), strLine.end(), ']');

    if (cntrOpen == cntrClose) {
        return true;
    }
    return false;
}

void Input::brackTest() {
    // handles [ ]
}

// if semicolon, erase
void Input::semicolon(queue<string>& q, string s) {
    if (s.size() != 0 && s.at(s.size()-1) == ';') {
        s.erase(s.size()-1);
        q.push(s);
        q.push(";");
    }
    else {
        q.push(s);
    }
}

// returns a queue of parsed string
queue<string> Input::Parse() {
    // checks if there's anything
    // cout << "test: " << strLine << endl;

    // clears tasks queue
    queue<string> empty;
    swap(tasks, empty);

    if (strLine.size() == 0) {
        return tasks;
    }

    // checks if string has only spaces
    if (strLine.find_first_not_of(' ') == string::npos) {
        return tasks;
    }

    istringstream iss(strLine);

    // iss >> ws;
    string token;
    string cmd;
    // end used to determine if its end of user input
    bool end = true;
    bool start = true;
    // if a connector was just detected
    bool con = false;
    // if there is a parentheses
    bool paren = false;
    bool tested = false;

    // ignores ' '
    while (getline(iss, token, ' ')) {
         if ( (start && token == "test") || (con && token == "test" )) {
            tasks.push(token);
            if (getline(iss, token, ' ')) {
                if (token == "-e" || token == "-f" || token == "-d") {
                    tasks.push(token);
                    if (getline(iss, token, ' ')) {
                        // tasks.push(token);
                        semicolon(tasks, token);
                    }
                    // strLine empty
                    else {return tasks;}
                }
                else if (token != "&&" && token != "||" && token != ";") {
                    tasks.push("-e");
                    // tasks.push(token);
                    semicolon(tasks, token);
                }
                else if (token == "&&" || token == "||" || token == ";") {
                    // tasks.push(token);
                    semicolon(tasks, token);
                }
            }
            end = false;
            tested = true;
        }

        // removed else if
         else if (token == "&&" || token == "||" || token == ";"  ||
                 token == "(" || token == ")") {
            // pushes whatever cmd was
            // if (!tested) {
            if (!cmd.empty()) {
                tasks.push(cmd);
            }
            // makes string empty
            cmd.clear();
            // pushes &&, ||, or ;
            tasks.push(token);
            if (token == "(") {paren = true;}
            end = false;
            con = true;
            tested = false;
        }

        // if you see [, keep reading til you see ]
        else if ( (start && token == "[") || (con && token == "[") ) {
            tasks.push(token);
            while (token != "]") {
                if (getline(iss, token, ' ')) {
                    // tasks.push(token);
                    semicolon(tasks, token);
                }
                // empty
                else {return tasks;}
            }
            end = false;
            con = false;
            tested = false;
        }

	    // would see if the first char of token is
	    // ( then would push ( delete it from
	    // the token then push the actual token in
	    // would set paren to true letting
	    // it know that there is a closing
	    // paren to look for

	    else if (token.at(0) == '(') {
            while (token.at(0) == '(') {
	            paren = true;
    	        tasks.push("(");
	            token.erase(0, 1);
	            // tasks.push(token);
                if (cmd.empty()) {
                    cmd = token;
                }
                else {
                    cmd = " " + token;
                }
            }
            end = false;
            con = false;
	    }

	    // would check to see if paren is true
	    // and would see is the last char in
	    // token is ) then would erase ) from token
	    // push the token in push the
	    // ) in and make paren false again
	    // so that it know the braket is closed
	    else if (paren == true && token.at(token.size() - 1) == ')') {
            while (token.at(token.size() - 1) == ')') {
                token.erase(token.size()-1);
                if (cmd.empty()) {
                    tasks.push(token);
                }
                else {
                    tasks.push(cmd + " " + token);
                    cmd.clear();
                }
	            // tasks.push(token);
	            tasks.push(")");
            }
	        // paren = false;
            end = false;
            con = false;
	    }
        // else if not a connector

        // else if (strLine.find("&&") != std::string::npos) {
        //     cout << "found &&" << endl;
            // find position and split up string accordingly
        // }

        else { //if (!tested) {
            // check if end of token has semicolon
            // remove the extra spaces
            // cout << "token: " << token << token.size() << endl;
            if (token.size() != 0 && token.at(token.size() - 1) == ';') {
                token.erase(token.size()-1);
                if (cmd.empty()) {
                    tasks.push(token);
                }
                else {
                    tasks.push(cmd + " " + token);
                    cmd.clear();
                }
                tasks.push(";");
                end = false;
            }

            // check if connectors are hidden in words

            // no semicolon detected at end of word
            else {
                if (cmd.empty()) {
                    cmd = token;
                }
                else {
                    cmd = cmd + " " + token;
                }
                end = true;
            }
            con = false;
            tested = false;
        }

        start = false;
    }

    // if no more connectors were detected
    if (end) {
        tasks.push(cmd);
    }

    // check if last thing in task is a && or ||
    // if (token == "&&" || token == "||") {
        // get user input again
    //     getInput();
    //     Parse();
    // }

    return tasks;
}

// converts a token to char**
char** Input::toChar(string a) {
    stringstream stream(a);
    string oneWord;
    int i = 0;
    char** c = new char*[1024];
    // one word at a time
    while (stream >> oneWord) {
        // allocating memory
        char* ptr = new char[oneWord.size() + 1];
        // copies string (converted to c-string) to ptr)
        memcpy(ptr, oneWord.c_str(), oneWord.size() + 1);
        c[i] = ptr;
        ++i;
    }

    // null terminates the char**
    c[i] = '\0';

    return c;
}

<commit_msg>should parse parentheses correctly<commit_after>#include <iostream>
#include "Input.h"
#include <queue>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
#include <algorithm>

using namespace std;

// void Input::setUser() {
// }

void Input::getInput() {
    strLine.clear();
    cout << "$ ";
    getline (cin, strLine);

    // if the user ONLY entered exit
    if (strLine == "exit") {
        cout << "You have exited shell." << endl;
        exit(0);
    }

    // if # spotted, cuts off # and everything after it
    size_t found = strLine.find('#');
    if (found != string::npos) {
        strLine.erase(strLine.begin() + found, strLine.end());
        if (strLine.size() == 0) {
            // cout << "nothing left" << endl;
        }
    }
}

bool Input::isTest() {
    size_t found = strLine.find('[');
    if (found != string::npos) {
        if ( validTest() ) {
            return true;
        }
        return false;
    }

    // check if test is first word in string or after connector
    if (strLine.find("test ") != string::npos) {
        return true;
    }

    return false;
}

// handle error when user puts something like "] [" wtf
bool Input::validTest() {
    size_t cntrOpen  = std::count(strLine.begin(), strLine.end(), '[');
    size_t cntrClose = std::count(strLine.begin(), strLine.end(), ']');

    if (cntrOpen == cntrClose) {
        return true;
    }
    return false;
}

void Input::brackTest() {
    // handles [ ]
}

// if semicolon, erase
void Input::semicolon(queue<string>& q, string s) {
    if (s.size() != 0 && s.at(s.size()-1) == ';') {
        s.erase(s.size()-1);
        q.push(s);
        q.push(";");
    }
    else {
        q.push(s);
    }
}

// returns a queue of parsed string
queue<string> Input::Parse() {
    // checks if there's anything
    // cout << "test: " << strLine << endl;

    // clears tasks queue
    queue<string> empty;
    swap(tasks, empty);

    if (strLine.size() == 0) {
        return tasks;
    }

    // checks if string has only spaces
    if (strLine.find_first_not_of(' ') == string::npos) {
        return tasks;
    }

    istringstream iss(strLine);

    // iss >> ws;
    string token;
    string cmd;
    // end used to determine if its end of user input
    bool end = true;
    bool start = true;
    // if a connector was just detected
    bool con = false;
    // if there is a parentheses
    bool paren = false;
    bool tested = false;

    // ignores ' '
    while (getline(iss, token, ' ')) {
         if ( (start && token == "test") || (con && token == "test" )) {
            tasks.push(token);
            if (getline(iss, token, ' ')) {
                if (token == "-e" || token == "-f" || token == "-d") {
                    tasks.push(token);
                    if (getline(iss, token, ' ')) {
                        // tasks.push(token);
                        semicolon(tasks, token);
                    }
                    // strLine empty
                    else {return tasks;}
                }
                else if (token != "&&" && token != "||" && token != ";") {
                    tasks.push("-e");
                    // tasks.push(token);
                    semicolon(tasks, token);
                }
                else if (token == "&&" || token == "||" || token == ";") {
                    // tasks.push(token);
                    semicolon(tasks, token);
                }
            }
            end = false;
            tested = true;
        }

        // removed else if
         else if (token == "&&" || token == "||" || token == ";"  ||
                 token == "(" || token == ")") {
            // pushes whatever cmd was
            // if (!tested) {
            if (!cmd.empty()) {
                tasks.push(cmd);
            }
            // makes string empty
            cmd.clear();
            // pushes &&, ||, or ;
            tasks.push(token);
            if (token == "(") {paren = true;}
            end = false;
            con = true;
            tested = false;
        }

        // if you see [, keep reading til you see ]
        else if ( (start && token == "[") || (con && token == "[") ) {
            tasks.push(token);
            while (token != "]") {
                if (getline(iss, token, ' ')) {
                    // tasks.push(token);
                    semicolon(tasks, token);
                }
                // empty
                else {return tasks;}
            }
            end = false;
            con = false;
            tested = false;
        }

	    // would see if the first char of token is
	    // ( then would push ( delete it from
	    // the token then push the actual token in
	    // would set paren to true letting
	    // it know that there is a closing
	    // paren to look for

	    else if (token.at(0) == '(') {
            while (token.at(0) == '(') {
	            paren = true;
    	        tasks.push("(");
	            token.erase(0, 1);
	            // tasks.push(token);
                if (cmd.empty() && !token.empty() && token.at(0) != '(') {
                    cmd = token;
                }
                else if (!cmd.empty()) {
                    cmd += " " + token;
                }
            }
            end = false;
            con = false;
	    }

	    // would check to see if paren is true
	    // and would see is the last char in
	    // token is ) then would erase ) from token
	    // push the token in push the
	    // ) in and make paren false again
	    // so that it know the braket is closed
	    else if (paren == true && token.at(token.size() - 1) == ')') {
            int count = 0;
            while (token.at(token.size() - 1) == ')') {
                token.erase(token.size()-1);
                ++count;
                if (cmd.empty() && !token.empty() && token.at(0) != ')') {
                    // cout << "1: " << token << endl;
                    // tasks.push(token);
                    cmd = token;
                }
                else if (!cmd.empty() && token.at(token.size()-1) != ')') {
                    // tasks.push(cmd + " " + token);
                    // cmd.clear();
                    cmd += " " + token;
                }
	            // tasks.push(token);
	            // tasks.push(")");
            }
            tasks.push(cmd);
            cmd.clear();
	        // paren = false;
            while (count != 0) {
                tasks.push(")");
                count -= 1;
            }
            end = false;
            con = false;
	    }
        // else if not a connector

        // else if (strLine.find("&&") != std::string::npos) {
        //     cout << "found &&" << endl;
            // find position and split up string accordingly
        // }

        else { //if (!tested) {
            // check if end of token has semicolon
            // remove the extra spaces
            // cout << "token: " << token << token.size() << endl;
            if (token.size() != 0 && token.at(token.size() - 1) == ';') {
                token.erase(token.size()-1);
                if (cmd.empty()) {
                    tasks.push(token);
                }
                else {
                    tasks.push(cmd + " " + token);
                    cmd.clear();
                }
                tasks.push(";");
                end = false;
            }

            // check if connectors are hidden in words

            // no semicolon detected at end of word
            else {
                if (cmd.empty()) {
                    cmd = token;
                }
                else {
                    cmd = cmd + " " + token;
                }
                end = true;
            }
            con = false;
            tested = false;
        }

        start = false;
    }

    // if no more connectors were detected
    if (end) {
        tasks.push(cmd);
    }

    // check if last thing in task is a && or ||
    // if (token == "&&" || token == "||") {
        // get user input again
    //     getInput();
    //     Parse();
    // }

    return tasks;
}

// converts a token to char**
char** Input::toChar(string a) {
    stringstream stream(a);
    string oneWord;
    int i = 0;
    char** c = new char*[1024];
    // one word at a time
    while (stream >> oneWord) {
        // allocating memory
        char* ptr = new char[oneWord.size() + 1];
        // copies string (converted to c-string) to ptr)
        memcpy(ptr, oneWord.c_str(), oneWord.size() + 1);
        c[i] = ptr;
        ++i;
    }

    // null terminates the char**
    c[i] = '\0';

    return c;
}

<|endoftext|>


<commit_before>#include "Ising.h"
#include <math.h>
#include <assert.h>

#define SQUARED(x) x*x

namespace ising {
    inline int s(char x,char y,char z) {
        return (x<<2) + (y<<1) + (z);
    }

    inline int boundsCheck(int x, const int max) {
        if (x < 0) {
            return max + x;
        }
        return x % max;
    }
}

using namespace ising;

int IsingReservoir::interactWithBit(int bit) {
    if (currentState->bit != bit) {
        currentState=currentState->bitFlipState;
    }

    assert(ceil(constants.tau)>0 &&
           "Figure out how tau converts to discrete time.");
    int iterations = ceil(constants.tau);

    for (int k = 0; k<iterations; k++) {
        parity = 0;
        this->isingStep();
        this->wheelStep();
    }

    return currentState->bit;
}

inline int IsingReservoir::isingStep() {
    int row = 0;
    int column = (currentStepType == odd ? row + 1 : row) % 2;
    while (row<isingSide) {
        while (column<isingSide) {
            Coordinate coord(row,column);
            //Evolve each cell.
            char &cell = getCell(coord);
            if (countHighNeighbors(coord) == 2) {
                cell = (cell + 1) % 2;
            }
            parity += cell;

            column+=2;
        }
        row++;
        column = (currentStepType == odd ? row + 1 : row) % 2;
    }
}

inline void IsingReservoir::wheelStep() {
    char &s1 = getCell(interactionCells.first);
    char &s2 = getCell(interactionCells.second);

    int inputState = s(s1,s2,parity % 2);

    SystemState *lastState = currentState;
    TransitionTable currentTable = transitions[currentState];
    SystemState *nextState = currentTable[inputState];

    assert(currentTable.size());
    assert(nextState);

    currentState = nextState;
}

inline int IsingReservoir::countHighNeighbors(Coordinate c) {
    int value = 0;
    for (int k = 0; k<4; k++) {
        Coordinate neighbor;
        switch (k) {
            case 0: // North
                neighbor.x = c.x;
                neighbor.y = c.y - 1;
                break;

            case 1: // South
                neighbor.x = c.x;
                neighbor.y = c.y + 1;
                break;

            case 2: // East
                neighbor.x = c.x - 1;
                neighbor.y = c.y;
                break;

            case 3: // West
                neighbor.x = c.x + 1;
                neighbor.y = c.y;
                break;

            default: // We should never be here.
                assert(0 && "Unreachable.");
                break;
        }
        neighbor.x = boundsCheck(neighbor.x, isingSide);
        neighbor.y = boundsCheck(neighbor.y, isingSide);
        value +=getCell(neighbor);
    }
    return value;
}

void IsingReservoir::initializeCellsWithRNG(gsl_rng *RNG, int N) {
    for (int k=0; k<SQUARED(this->isingSide); k++) {
        int row = (int)(k % this->isingSide);
        int column = (int)(k / this->isingSide);

        //Randomize the cells.
        this->cells[column][row] = gsl_rng_uniform_int(RNG,2);
    }

    // The metropolis algorithm!
    for (int k=0; k<N; k++) {
        Coordinate coord;
        coord.x = gsl_rng_uniform_int(RNG,isingSide);
        coord.y = gsl_rng_uniform_int(RNG,isingSide);

        char &cell = getCell(coord);

        int dE = 0;
        if (cell == 0) {
            dE = 4 - 2 * countHighNeighbors(coord);
        } else {
            //dE = 4 - 2 * (4 - countHigh(neighbors));
            //dE = 4 - 8 + 2 * countHigh(neighbors);
            dE = 2 * countHighNeighbors(coord) - 4;
        }

        // TODO: Memoize me.
        if ( exp(constants.beta() * dE) < gsl_rng_uniform(RNG) ) {
            char &cell = getCell(coord);
            cell = (cell + 1) % 2;
        }
    }
}

inline char &IsingReservoir::getCell(const Coordinate c) {
    //FIXME: Bounds check?
    return cells[c.y][c.x];
}

inline int IsingReservoir::countHigh(CoordinateList list) {
    int highCount = 0;
    for (CoordIterator it = list.begin(); it!=list.end(); ++it) {
        if (getCell(*it) == 1) {
            ++highCount;
        }
    }
    return highCount;
}

IsingReservoir::CoordinateList IsingReservoir::getNeighbors(const Coordinate c){
    std::vector<Coordinate> neighbors(4);
    for (int k = 0; k<4; k++) {
        Coordinate neighbor;
        switch (k) {
            case 0: // North
                neighbor.x = c.x;
                neighbor.y = c.y - 1;
                break;

            case 1: // South
                neighbor.x = c.x;
                neighbor.y = c.y + 1;
                break;

            case 2: // East
                neighbor.x = c.x - 1;
                neighbor.y = c.y;
                break;

            case 3: // West
                neighbor.x = c.x + 1;
                neighbor.y = c.y;
                break;

            default: // We should never be here.
                assert(0 && "Unreachable.");
                break;
        }
        neighbor.x = boundsCheck(neighbor.x, isingSide);
        neighbor.y = boundsCheck(neighbor.y, isingSide);
        neighbors.push_back(neighbor);
    }
    return neighbors;
}

IsingReservoir::~IsingReservoir() {
    for (int k=0; k<this->isingSide; k++) {
        delete [] cells[k];
    }
    delete [] cells;
}

IsingReservoir::IsingReservoir(gsl_rng *RNG, Constants constants, int IS) : Reservoir(constants), isingSide(IS) {
    setupStateTable();
    this->cells = new char *[IS];
    for (int k=0; k<IS; k++) {
        this->cells[k]=new char[IS];
    }
    this->initializeCellsWithRNG(RNG);
}

inline void IsingReservoir::setupStateTable() {
    //TODO: Custom states. This is goofy.
    //Source: http://imgur.com/FF5TBQh

    #define init(XX,StateXX) \
                TransitionTable XX;\
                for (char k=0; k<8; k++) \
                    XX[k]=&StateXX;
    init(A1,StateA1);
    A1[s(0,0,1)] = &StateB1;
    A1[s(1,0,1)] = &StateB1;
    transitions[&StateA1]=A1;

    init(B1,StateB1);
    B1[s(0,0,1)] = &StateA1;
    B1[s(1,0,1)] = &StateA1;
    B1[s(1,1,1)] = &StateC1;
    B1[s(0,1,1)] = &StateC1;
    transitions[&StateB1]=B1;

    init(C1,StateC1);
    C1[s(0,1,1)] = &StateB1;
    C1[s(1,1,1)] = &StateB1;
    C1[s(0,0,1)] = &StateA0;
    C1[s(0,0,0)] = &StateA0;
    transitions[&StateC1]=C1;

    init(A0,StateA0);
    A0[s(0,1,0)] = &StateC1;
    A0[s(0,1,1)] = &StateC1;
    A0[s(1,0,1)] = &StateB0;
    A0[s(0,0,1)] = &StateB0;
    transitions[&StateA0]=A0;

    init(B0,StateB0);
    B0[s(0,0,1)] = &StateB0;
    B0[s(1,0,1)] = &StateB0;
    B0[s(1,1,1)] = &StateA0;
    B0[s(0,1,1)] = &StateA0;
    transitions[&StateB0] = B0;

    init(C0,StateC0);
    C0[s(1,1,1)] = &StateB0;
    C0[s(0,1,1)] = &StateB0;
    transitions[&StateC0] = C0;
    //TODO: TEST ME.
}

Reservoir *IsingReservoir::IsingFactory::create(gsl_rng *RNG, Constants constants) {
    return new IsingReservoir(RNG,constants,dimension);
}
<commit_msg>Alternate the step type.<commit_after>#include "Ising.h"
#include <math.h>
#include <assert.h>

#define SQUARED(x) x*x

namespace ising {
    inline int s(char x,char y,char z) {
        return (x<<2) + (y<<1) + (z);
    }

    inline int boundsCheck(int x, const int max) {
        if (x < 0) {
            return max + x;
        }
        return x % max;
    }
}

using namespace ising;

int IsingReservoir::interactWithBit(int bit) {
    if (currentState->bit != bit) {
        currentState=currentState->bitFlipState;
    }

    assert(ceil(constants.tau)>0 &&
           "Figure out how tau converts to discrete time.");
    int iterations = ceil(constants.tau);

    for (int k = 0; k<iterations; k++) {
        parity = 0;
        this->isingStep();
        this->wheelStep();
    }

    return currentState->bit;
}

inline int IsingReservoir::isingStep() {
    int row = 0;
    int column = (currentStepType == odd ? row + 1 : row) % 2;
    while (row<isingSide) {
        while (column<isingSide) {
            Coordinate coord(row,column);
            //Evolve each cell.
            char &cell = getCell(coord);
            if (countHighNeighbors(coord) == 2) {
                cell = (cell + 1) % 2;
            }
            parity += cell;

            column+=2;
        }
        row++;
        column = (currentStepType == odd ? row + 1 : row) % 2;
    }
    currentStepType = (currentStepType == odd) ? even : odd;
}

inline void IsingReservoir::wheelStep() {
    char &s1 = getCell(interactionCells.first);
    char &s2 = getCell(interactionCells.second);

    int inputState = s(s1,s2,parity % 2);

    SystemState *lastState = currentState;
    TransitionTable currentTable = transitions[currentState];
    SystemState *nextState = currentTable[inputState];

    assert(currentTable.size());
    assert(nextState);

    currentState = nextState;
}

inline int IsingReservoir::countHighNeighbors(Coordinate c) {
    int value = 0;
    for (int k = 0; k<4; k++) {
        Coordinate neighbor;
        switch (k) {
            case 0: // North
                neighbor.x = c.x;
                neighbor.y = c.y - 1;
                break;

            case 1: // South
                neighbor.x = c.x;
                neighbor.y = c.y + 1;
                break;

            case 2: // East
                neighbor.x = c.x - 1;
                neighbor.y = c.y;
                break;

            case 3: // West
                neighbor.x = c.x + 1;
                neighbor.y = c.y;
                break;

            default: // We should never be here.
                assert(0 && "Unreachable.");
                break;
        }
        neighbor.x = boundsCheck(neighbor.x, isingSide);
        neighbor.y = boundsCheck(neighbor.y, isingSide);
        value +=getCell(neighbor);
    }
    return value;
}

void IsingReservoir::initializeCellsWithRNG(gsl_rng *RNG, int N) {
    for (int k=0; k<SQUARED(this->isingSide); k++) {
        int row = (int)(k % this->isingSide);
        int column = (int)(k / this->isingSide);

        //Randomize the cells.
        this->cells[column][row] = gsl_rng_uniform_int(RNG,2);
    }

    // The metropolis algorithm!
    for (int k=0; k<N; k++) {
        Coordinate coord;
        coord.x = gsl_rng_uniform_int(RNG,isingSide);
        coord.y = gsl_rng_uniform_int(RNG,isingSide);

        char &cell = getCell(coord);

        int dE = 0;
        if (cell == 0) {
            dE = 4 - 2 * countHighNeighbors(coord);
        } else {
            //dE = 4 - 2 * (4 - countHigh(neighbors));
            //dE = 4 - 8 + 2 * countHigh(neighbors);
            dE = 2 * countHighNeighbors(coord) - 4;
        }

        // TODO: Memoize me.
        if ( exp(constants.beta() * dE) < gsl_rng_uniform(RNG) ) {
            char &cell = getCell(coord);
            cell = (cell + 1) % 2;
        }
    }
}

inline char &IsingReservoir::getCell(const Coordinate c) {
    //FIXME: Bounds check?
    return cells[c.y][c.x];
}

inline int IsingReservoir::countHigh(CoordinateList list) {
    int highCount = 0;
    for (CoordIterator it = list.begin(); it!=list.end(); ++it) {
        if (getCell(*it) == 1) {
            ++highCount;
        }
    }
    return highCount;
}

IsingReservoir::CoordinateList IsingReservoir::getNeighbors(const Coordinate c){
    std::vector<Coordinate> neighbors(4);
    for (int k = 0; k<4; k++) {
        Coordinate neighbor;
        switch (k) {
            case 0: // North
                neighbor.x = c.x;
                neighbor.y = c.y - 1;
                break;

            case 1: // South
                neighbor.x = c.x;
                neighbor.y = c.y + 1;
                break;

            case 2: // East
                neighbor.x = c.x - 1;
                neighbor.y = c.y;
                break;

            case 3: // West
                neighbor.x = c.x + 1;
                neighbor.y = c.y;
                break;

            default: // We should never be here.
                assert(0 && "Unreachable.");
                break;
        }
        neighbor.x = boundsCheck(neighbor.x, isingSide);
        neighbor.y = boundsCheck(neighbor.y, isingSide);
        neighbors.push_back(neighbor);
    }
    return neighbors;
}

IsingReservoir::~IsingReservoir() {
    for (int k=0; k<this->isingSide; k++) {
        delete [] cells[k];
    }
    delete [] cells;
}

IsingReservoir::IsingReservoir(gsl_rng *RNG, Constants constants, int IS) : Reservoir(constants), isingSide(IS) {
    setupStateTable();
    this->cells = new char *[IS];
    for (int k=0; k<IS; k++) {
        this->cells[k]=new char[IS];
    }
    this->initializeCellsWithRNG(RNG);
}

inline void IsingReservoir::setupStateTable() {
    //TODO: Custom states. This is goofy.
    //Source: http://imgur.com/FF5TBQh

    #define init(XX,StateXX) \
                TransitionTable XX;\
                for (char k=0; k<8; k++) \
                    XX[k]=&StateXX;
    init(A1,StateA1);
    A1[s(0,0,1)] = &StateB1;
    A1[s(1,0,1)] = &StateB1;
    transitions[&StateA1]=A1;

    init(B1,StateB1);
    B1[s(0,0,1)] = &StateA1;
    B1[s(1,0,1)] = &StateA1;
    B1[s(1,1,1)] = &StateC1;
    B1[s(0,1,1)] = &StateC1;
    transitions[&StateB1]=B1;

    init(C1,StateC1);
    C1[s(0,1,1)] = &StateB1;
    C1[s(1,1,1)] = &StateB1;
    C1[s(0,0,1)] = &StateA0;
    C1[s(0,0,0)] = &StateA0;
    transitions[&StateC1]=C1;

    init(A0,StateA0);
    A0[s(0,1,0)] = &StateC1;
    A0[s(0,1,1)] = &StateC1;
    A0[s(1,0,1)] = &StateB0;
    A0[s(0,0,1)] = &StateB0;
    transitions[&StateA0]=A0;

    init(B0,StateB0);
    B0[s(0,0,1)] = &StateB0;
    B0[s(1,0,1)] = &StateB0;
    B0[s(1,1,1)] = &StateA0;
    B0[s(0,1,1)] = &StateA0;
    transitions[&StateB0] = B0;

    init(C0,StateC0);
    C0[s(1,1,1)] = &StateB0;
    C0[s(0,1,1)] = &StateB0;
    transitions[&StateC0] = C0;
    //TODO: TEST ME.
}

Reservoir *IsingReservoir::IsingFactory::create(gsl_rng *RNG, Constants constants) {
    return new IsingReservoir(RNG,constants,dimension);
}
<|endoftext|>