<commit_before>#include "antsUtilities.h"
#include <algorithm>

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

#include "itkDeformationFieldGradientTensorImageFilter.h"
#include "itkDeterminantTensorImageFilter.h"
#include "itkGeometricJacobianDeterminantImageFilter.h"
#include "itkLogImageFilter.h"
#include "itkMaximumImageFilter.h"

namespace ants
{
template <unsigned int ImageDimension>
int CreateJacobianDeterminantImage( int argc, char *argv[] )
{
  typedef double RealType;
  typedef itk::Image<RealType, ImageDimension> ImageType;
  typedef itk::Vector<RealType, ImageDimension> VectorType;
  typedef itk::Image<VectorType, ImageDimension> VectorImageType;

  /**
   * Read in vector field
   */
  typedef itk::ImageFileReader<VectorImageType> ReaderType;
  typename ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName( argv[2] );
  reader->Update();

  typename ImageType::Pointer jacobian = NULL;

  typename ImageType::Pointer minimumConstantImage = ImageType::New();
  minimumConstantImage->CopyInformation( reader->GetOutput() );
  minimumConstantImage->SetRegions( reader->GetOutput()->GetRequestedRegion() );
  minimumConstantImage->Allocate();
  minimumConstantImage->FillBuffer( 0.001 );

  bool calculateLogJacobian = false;
  if ( argc > 4 )
    {
    calculateLogJacobian = static_cast<bool>( atoi( argv[4] ) );
    }

  bool calculateGeometricJacobian = false;
  if ( argc > 5 )
    {
    calculateGeometricJacobian = static_cast<bool>( atoi( argv[5] ) );
    }

  if( calculateGeometricJacobian )
    {
    typedef itk::GeometricJacobianDeterminantImageFilter
      <VectorImageType, RealType, ImageType> JacobianFilterType;
    typename JacobianFilterType::Pointer jacobianFilter = JacobianFilterType::New();
    jacobianFilter->SetInput( reader->GetOutput() );

    jacobian = jacobianFilter->GetOutput();
    jacobian->Update();
    jacobian->DisconnectPipeline();
    }
  else
    {
    typedef itk::DeformationFieldGradientTensorImageFilter<VectorImageType, RealType> JacobianFilterType;
    typename JacobianFilterType::Pointer jacobianFilter = JacobianFilterType::New();
    jacobianFilter->SetInput( reader->GetOutput() );
    jacobianFilter->SetCalculateJacobian( true );
    jacobianFilter->SetUseImageSpacing( true );
    jacobianFilter->SetOrder( 2 );
    jacobianFilter->SetUseCenteredDifference( true );

    typedef itk::DeterminantTensorImageFilter<typename JacobianFilterType::OutputImageType, RealType>
      DeterminantFilterType;
    typename DeterminantFilterType::Pointer determinantFilter = DeterminantFilterType::New();
    determinantFilter->SetInput( jacobianFilter->GetOutput() );
    determinantFilter->Update();

    minimumConstantImage->FillBuffer( 0.0 );

    typedef itk::MaximumImageFilter<ImageType, ImageType, ImageType> MaxFilterType;
    typename MaxFilterType::Pointer maxFilter = MaxFilterType::New();
    maxFilter->SetInput1( determinantFilter->GetOutput() );
    maxFilter->SetInput2( minimumConstantImage );

    jacobian = maxFilter->GetOutput();
    jacobian->Update();
    jacobian->DisconnectPipeline();
    }

  if( calculateLogJacobian )
    {
    minimumConstantImage->FillBuffer( 0.001 );

    typedef itk::MaximumImageFilter<ImageType, ImageType, ImageType> MaxFilterType;
    typename MaxFilterType::Pointer maxFilter = MaxFilterType::New();
    maxFilter->SetInput1( jacobian );
    maxFilter->SetInput2( minimumConstantImage );

    typedef itk::LogImageFilter<ImageType, ImageType> LogFilterType;
    typename LogFilterType::Pointer logFilter = LogFilterType::New();
    logFilter->SetInput( maxFilter->GetOutput() );
    logFilter->Update();

    typedef itk::ImageFileWriter<ImageType> ImageWriterType;
    typename ImageWriterType::Pointer writer = ImageWriterType::New();
    writer->SetFileName( argv[3] );
    writer->SetInput( logFilter->GetOutput() );
    writer->Update();
    }
  else
    {
    typedef itk::ImageFileWriter<ImageType> ImageWriterType;
    typename ImageWriterType::Pointer writer = ImageWriterType::New();
    writer->SetFileName( argv[3] );
    writer->SetInput( jacobian );
    writer->Update();
    }

  return EXIT_SUCCESS;
}

// entry point for the library; parameter 'args' is equivalent to 'argv' in (argc,argv) of commandline parameters to
// 'main()'
int CreateJacobianDeterminantImage( std::vector<std::string> args, std::ostream* itkNotUsed( out_stream ) )
{
  // put the arguments coming in as 'args' into standard (argc,argv) format;
  // 'args' doesn't have the command name as first, argument, so add it manually;
  // 'args' may have adjacent arguments concatenated into one argument,
  // which the parser should handle
  args.insert( args.begin(), "CreateJacobianDeterminantImage" );

  int     argc = args.size();
  char* * argv = new char *[args.size() + 1];
  for( unsigned int i = 0; i < args.size(); ++i )
    {
    // allocate space for the string plus a null character
    argv[i] = new char[args[i].length() + 1];
    std::strncpy( argv[i], args[i].c_str(), args[i].length() );
    // place the null character in the end
    argv[i][args[i].length()] = '\0';
    }
  argv[argc] = 0;
  // class to automatically cleanup argv upon destruction
  class Cleanup_argv
  {
public:
    Cleanup_argv( char* * argv_, int argc_plus_one_ ) : argv( argv_ ), argc_plus_one( argc_plus_one_ )
    {
    }

    ~Cleanup_argv()
    {
      for( unsigned int i = 0; i < argc_plus_one; ++i )
        {
        delete[] argv[i];
        }
      delete[] argv;
    }

private:
    char* *      argv;
    unsigned int argc_plus_one;
  };
  Cleanup_argv cleanup_argv( argv, argc + 1 );

  // antscout->set_stream( out_stream );

  if( argc < 3 )
    {
    std::cout << "Usage: " << argv[0] << " ImageDimension deformationField outputImage log-jac?(default-false)"
             << std::endl;
    return EXIT_FAILURE;
    }

  switch( atoi( argv[1] ) )
    {
    case 2:
      {
      CreateJacobianDeterminantImage<2>( argc, argv );
      }
      break;
    case 3:
      {
      CreateJacobianDeterminantImage<3>( argc, argv );
      }
      break;
    default:
      std::cout << "Unsupported dimension" << std::endl;
      return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}
} // namespace ants
<commit_msg>DOC:  Fixed command line.<commit_after>#include "antsUtilities.h"
#include <algorithm>

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

#include "itkDeformationFieldGradientTensorImageFilter.h"
#include "itkDeterminantTensorImageFilter.h"
#include "itkGeometricJacobianDeterminantImageFilter.h"
#include "itkLogImageFilter.h"
#include "itkMaximumImageFilter.h"

namespace ants
{
template <unsigned int ImageDimension>
int CreateJacobianDeterminantImage( int argc, char *argv[] )
{
  typedef double RealType;
  typedef itk::Image<RealType, ImageDimension> ImageType;
  typedef itk::Vector<RealType, ImageDimension> VectorType;
  typedef itk::Image<VectorType, ImageDimension> VectorImageType;

  /**
   * Read in vector field
   */
  typedef itk::ImageFileReader<VectorImageType> ReaderType;
  typename ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName( argv[2] );
  reader->Update();

  typename ImageType::Pointer jacobian = NULL;

  typename ImageType::Pointer minimumConstantImage = ImageType::New();
  minimumConstantImage->CopyInformation( reader->GetOutput() );
  minimumConstantImage->SetRegions( reader->GetOutput()->GetRequestedRegion() );
  minimumConstantImage->Allocate();
  minimumConstantImage->FillBuffer( 0.001 );

  bool calculateLogJacobian = false;
  if ( argc > 4 )
    {
    calculateLogJacobian = static_cast<bool>( atoi( argv[4] ) );
    }

  bool calculateGeometricJacobian = false;
  if ( argc > 5 )
    {
    calculateGeometricJacobian = static_cast<bool>( atoi( argv[5] ) );
    }

  if( calculateGeometricJacobian )
    {
    typedef itk::GeometricJacobianDeterminantImageFilter
      <VectorImageType, RealType, ImageType> JacobianFilterType;
    typename JacobianFilterType::Pointer jacobianFilter = JacobianFilterType::New();
    jacobianFilter->SetInput( reader->GetOutput() );

    jacobian = jacobianFilter->GetOutput();
    jacobian->Update();
    jacobian->DisconnectPipeline();
    }
  else
    {
    typedef itk::DeformationFieldGradientTensorImageFilter<VectorImageType, RealType> JacobianFilterType;
    typename JacobianFilterType::Pointer jacobianFilter = JacobianFilterType::New();
    jacobianFilter->SetInput( reader->GetOutput() );
    jacobianFilter->SetCalculateJacobian( true );
    jacobianFilter->SetUseImageSpacing( true );
    jacobianFilter->SetOrder( 2 );
    jacobianFilter->SetUseCenteredDifference( true );

    typedef itk::DeterminantTensorImageFilter<typename JacobianFilterType::OutputImageType, RealType>
      DeterminantFilterType;
    typename DeterminantFilterType::Pointer determinantFilter = DeterminantFilterType::New();
    determinantFilter->SetInput( jacobianFilter->GetOutput() );
    determinantFilter->Update();

    minimumConstantImage->FillBuffer( 0.0 );

    typedef itk::MaximumImageFilter<ImageType, ImageType, ImageType> MaxFilterType;
    typename MaxFilterType::Pointer maxFilter = MaxFilterType::New();
    maxFilter->SetInput1( determinantFilter->GetOutput() );
    maxFilter->SetInput2( minimumConstantImage );

    jacobian = maxFilter->GetOutput();
    jacobian->Update();
    jacobian->DisconnectPipeline();
    }

  if( calculateLogJacobian )
    {
    minimumConstantImage->FillBuffer( 0.001 );

    typedef itk::MaximumImageFilter<ImageType, ImageType, ImageType> MaxFilterType;
    typename MaxFilterType::Pointer maxFilter = MaxFilterType::New();
    maxFilter->SetInput1( jacobian );
    maxFilter->SetInput2( minimumConstantImage );

    typedef itk::LogImageFilter<ImageType, ImageType> LogFilterType;
    typename LogFilterType::Pointer logFilter = LogFilterType::New();
    logFilter->SetInput( maxFilter->GetOutput() );
    logFilter->Update();

    typedef itk::ImageFileWriter<ImageType> ImageWriterType;
    typename ImageWriterType::Pointer writer = ImageWriterType::New();
    writer->SetFileName( argv[3] );
    writer->SetInput( logFilter->GetOutput() );
    writer->Update();
    }
  else
    {
    typedef itk::ImageFileWriter<ImageType> ImageWriterType;
    typename ImageWriterType::Pointer writer = ImageWriterType::New();
    writer->SetFileName( argv[3] );
    writer->SetInput( jacobian );
    writer->Update();
    }

  return EXIT_SUCCESS;
}

// entry point for the library; parameter 'args' is equivalent to 'argv' in (argc,argv) of commandline parameters to
// 'main()'
int CreateJacobianDeterminantImage( std::vector<std::string> args, std::ostream* itkNotUsed( out_stream ) )
{
  // put the arguments coming in as 'args' into standard (argc,argv) format;
  // 'args' doesn't have the command name as first, argument, so add it manually;
  // 'args' may have adjacent arguments concatenated into one argument,
  // which the parser should handle
  args.insert( args.begin(), "CreateJacobianDeterminantImage" );

  int     argc = args.size();
  char* * argv = new char *[args.size() + 1];
  for( unsigned int i = 0; i < args.size(); ++i )
    {
    // allocate space for the string plus a null character
    argv[i] = new char[args[i].length() + 1];
    std::strncpy( argv[i], args[i].c_str(), args[i].length() );
    // place the null character in the end
    argv[i][args[i].length()] = '\0';
    }
  argv[argc] = 0;
  // class to automatically cleanup argv upon destruction
  class Cleanup_argv
  {
public:
    Cleanup_argv( char* * argv_, int argc_plus_one_ ) : argv( argv_ ), argc_plus_one( argc_plus_one_ )
    {
    }

    ~Cleanup_argv()
    {
      for( unsigned int i = 0; i < argc_plus_one; ++i )
        {
        delete[] argv[i];
        }
      delete[] argv;
    }

private:
    char* *      argv;
    unsigned int argc_plus_one;
  };
  Cleanup_argv cleanup_argv( argv, argc + 1 );

  // antscout->set_stream( out_stream );

  if( argc < 3 )
    {
    std::cout << "Usage: " << argv[0] << " imageDimension deformationField outputImage [doLogJacobian=0] [useGeometric=0]" << std::endl;
    return EXIT_FAILURE;
    }

  switch( atoi( argv[1] ) )
    {
    case 2:
      {
      CreateJacobianDeterminantImage<2>( argc, argv );
      }
      break;
    case 3:
      {
      CreateJacobianDeterminantImage<3>( argc, argv );
      }
      break;
    default:
      std::cout << "Unsupported dimension" << std::endl;
      return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}
} // namespace ants
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2015
// Mehdi Goli    Codeplay Software Ltd.
// Ralph Potter  Codeplay Software Ltd.
// Luke Iwanski  Codeplay Software Ltd.
// Contact: <eigen@codeplay.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#define EIGEN_TEST_NO_LONGDOUBLE
#define EIGEN_TEST_NO_COMPLEX
#define EIGEN_TEST_FUNC cxx11_tensor_reduction_sycl
#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
#define EIGEN_USE_SYCL

#include "main.h"
#include <unsupported/Eigen/CXX11/Tensor>

template <typename DataType, int DataLayout>
static void test_full_reductions_sycl(const Eigen::SyclDevice&  sycl_device) {

  const int num_rows = 452;
  const int num_cols = 765;
  array<int, 2> tensorRange = {{num_rows, num_cols}};

  Tensor<DataType, 2, DataLayout> in(tensorRange);
  Tensor<DataType, 0, DataLayout> full_redux;
  Tensor<DataType, 0, DataLayout> full_redux_gpu;

  in.setRandom();

  full_redux = in.sum();

  DataType* gpu_in_data = static_cast<DataType*>(sycl_device.allocate(in.dimensions().TotalSize()*sizeof(DataType)));
  DataType* gpu_out_data =(DataType*)sycl_device.allocate(sizeof(DataType));

  TensorMap<Tensor<DataType, 2, DataLayout> >  in_gpu(gpu_in_data, tensorRange);
  TensorMap<Tensor<DataType, 0, DataLayout> >  out_gpu(gpu_out_data);

  sycl_device.memcpyHostToDevice(gpu_in_data, in.data(),(in.dimensions().TotalSize())*sizeof(DataType));
  out_gpu.device(sycl_device) = in_gpu.sum();
  sycl_device.memcpyDeviceToHost(full_redux_gpu.data(), gpu_out_data, sizeof(DataType));
  // Check that the CPU and GPU reductions return the same result.
  VERIFY_IS_APPROX(full_redux_gpu(), full_redux());

  sycl_device.deallocate(gpu_in_data);
  sycl_device.deallocate(gpu_out_data);
}
template <typename DataType, int DataLayout>
static void test_first_dim_reductions_sycl(const Eigen::SyclDevice& sycl_device) {

  int dim_x = 145;
  int dim_y = 1;
  int dim_z = 67;

  array<int, 3> tensorRange = {{dim_x, dim_y, dim_z}};
  Eigen::array<int, 1> red_axis;
  red_axis[0] = 0;
  array<int, 2> reduced_tensorRange = {{dim_y, dim_z}};

  Tensor<DataType, 3, DataLayout> in(tensorRange);
  Tensor<DataType, 2, DataLayout> redux(reduced_tensorRange);
  Tensor<DataType, 2, DataLayout> redux_gpu(reduced_tensorRange);

  in.setRandom();

  redux= in.sum(red_axis);

  DataType* gpu_in_data = static_cast<DataType*>(sycl_device.allocate(in.dimensions().TotalSize()*sizeof(DataType)));
  DataType* gpu_out_data = static_cast<DataType*>(sycl_device.allocate(redux_gpu.dimensions().TotalSize()*sizeof(DataType)));

  TensorMap<Tensor<DataType, 3, DataLayout> >  in_gpu(gpu_in_data, tensorRange);
  TensorMap<Tensor<DataType, 2, DataLayout> >  out_gpu(gpu_out_data, reduced_tensorRange);

  sycl_device.memcpyHostToDevice(gpu_in_data, in.data(),(in.dimensions().TotalSize())*sizeof(DataType));
  out_gpu.device(sycl_device) = in_gpu.sum(red_axis);
  sycl_device.memcpyDeviceToHost(redux_gpu.data(), gpu_out_data, redux_gpu.dimensions().TotalSize()*sizeof(DataType));

  // Check that the CPU and GPU reductions return the same result.
  for(int j=0; j<reduced_tensorRange[0]; j++ )
    for(int k=0; k<reduced_tensorRange[1]; k++ )
      VERIFY_IS_APPROX(redux_gpu(j,k), redux(j,k));

  sycl_device.deallocate(gpu_in_data);
  sycl_device.deallocate(gpu_out_data);
}

template <typename DataType, int DataLayout>
static void test_last_dim_reductions_sycl(const Eigen::SyclDevice &sycl_device) {

  int dim_x = 567;
  int dim_y = 1;
  int dim_z = 47;

  array<int, 3> tensorRange = {{dim_x, dim_y, dim_z}};
  Eigen::array<int, 1> red_axis;
  red_axis[0] = 2;
  array<int, 2> reduced_tensorRange = {{dim_x, dim_y}};

  Tensor<DataType, 3, DataLayout> in(tensorRange);
  Tensor<DataType, 2, DataLayout> redux(reduced_tensorRange);
  Tensor<DataType, 2, DataLayout> redux_gpu(reduced_tensorRange);

  in.setRandom();

  redux= in.sum(red_axis);

  DataType* gpu_in_data = static_cast<DataType*>(sycl_device.allocate(in.dimensions().TotalSize()*sizeof(DataType)));
  DataType* gpu_out_data = static_cast<DataType*>(sycl_device.allocate(redux_gpu.dimensions().TotalSize()*sizeof(DataType)));

  TensorMap<Tensor<DataType, 3, DataLayout> >  in_gpu(gpu_in_data, tensorRange);
  TensorMap<Tensor<DataType, 2, DataLayout> >  out_gpu(gpu_out_data, reduced_tensorRange);

  sycl_device.memcpyHostToDevice(gpu_in_data, in.data(),(in.dimensions().TotalSize())*sizeof(DataType));
  out_gpu.device(sycl_device) = in_gpu.sum(red_axis);
  sycl_device.memcpyDeviceToHost(redux_gpu.data(), gpu_out_data, redux_gpu.dimensions().TotalSize()*sizeof(DataType));
  // Check that the CPU and GPU reductions return the same result.
  for(int j=0; j<reduced_tensorRange[0]; j++ )
    for(int k=0; k<reduced_tensorRange[1]; k++ )
      VERIFY_IS_APPROX(redux_gpu(j,k), redux(j,k));

  sycl_device.deallocate(gpu_in_data);
  sycl_device.deallocate(gpu_out_data);

}
template<typename DataType, typename dev_Selector> void sycl_reduction_test_per_device(dev_Selector s){
  QueueInterface queueInterface(s);
  auto sycl_device = Eigen::SyclDevice(&queueInterface);
  test_full_reductions_sycl<DataType, RowMajor>(sycl_device);
  test_first_dim_reductions_sycl<DataType, RowMajor>(sycl_device);
  test_last_dim_reductions_sycl<DataType, RowMajor>(sycl_device);
  test_full_reductions_sycl<DataType, ColMajor>(sycl_device);
  test_first_dim_reductions_sycl<DataType, ColMajor>(sycl_device);
  test_last_dim_reductions_sycl<DataType, ColMajor>(sycl_device);
}
void test_cxx11_tensor_reduction_sycl() {
  printf("Test on GPU: OpenCL\n");
  CALL_SUBTEST(sycl_reduction_test_per_device<float>((cl::sycl::gpu_selector())));
  printf("repeating the test on CPU: OpenCL\n");
  CALL_SUBTEST(sycl_reduction_test_per_device<float>((cl::sycl::cpu_selector())));
  printf("repeating the test on CPU: HOST\n");
  CALL_SUBTEST(sycl_reduction_test_per_device<float>((cl::sycl::host_selector())));
  printf("Test Passed******************\n" );
}
<commit_msg>Only runs the cxx11_tensor_reduction_sycl on devices that are available.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2015
// Mehdi Goli    Codeplay Software Ltd.
// Ralph Potter  Codeplay Software Ltd.
// Luke Iwanski  Codeplay Software Ltd.
// Contact: <eigen@codeplay.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#define EIGEN_TEST_NO_LONGDOUBLE
#define EIGEN_TEST_NO_COMPLEX
#define EIGEN_TEST_FUNC cxx11_tensor_reduction_sycl
#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
#define EIGEN_USE_SYCL

#include "main.h"
#include <unsupported/Eigen/CXX11/Tensor>

template <typename DataType, int DataLayout>
static void test_full_reductions_sycl(const Eigen::SyclDevice&  sycl_device) {

  const int num_rows = 452;
  const int num_cols = 765;
  array<int, 2> tensorRange = {{num_rows, num_cols}};

  Tensor<DataType, 2, DataLayout> in(tensorRange);
  Tensor<DataType, 0, DataLayout> full_redux;
  Tensor<DataType, 0, DataLayout> full_redux_gpu;

  in.setRandom();

  full_redux = in.sum();

  DataType* gpu_in_data = static_cast<DataType*>(sycl_device.allocate(in.dimensions().TotalSize()*sizeof(DataType)));
  DataType* gpu_out_data =(DataType*)sycl_device.allocate(sizeof(DataType));

  TensorMap<Tensor<DataType, 2, DataLayout> >  in_gpu(gpu_in_data, tensorRange);
  TensorMap<Tensor<DataType, 0, DataLayout> >  out_gpu(gpu_out_data);

  sycl_device.memcpyHostToDevice(gpu_in_data, in.data(),(in.dimensions().TotalSize())*sizeof(DataType));
  out_gpu.device(sycl_device) = in_gpu.sum();
  sycl_device.memcpyDeviceToHost(full_redux_gpu.data(), gpu_out_data, sizeof(DataType));
  // Check that the CPU and GPU reductions return the same result.
  VERIFY_IS_APPROX(full_redux_gpu(), full_redux());

  sycl_device.deallocate(gpu_in_data);
  sycl_device.deallocate(gpu_out_data);
}
template <typename DataType, int DataLayout>
static void test_first_dim_reductions_sycl(const Eigen::SyclDevice& sycl_device) {

  int dim_x = 145;
  int dim_y = 1;
  int dim_z = 67;

  array<int, 3> tensorRange = {{dim_x, dim_y, dim_z}};
  Eigen::array<int, 1> red_axis;
  red_axis[0] = 0;
  array<int, 2> reduced_tensorRange = {{dim_y, dim_z}};

  Tensor<DataType, 3, DataLayout> in(tensorRange);
  Tensor<DataType, 2, DataLayout> redux(reduced_tensorRange);
  Tensor<DataType, 2, DataLayout> redux_gpu(reduced_tensorRange);

  in.setRandom();

  redux= in.sum(red_axis);

  DataType* gpu_in_data = static_cast<DataType*>(sycl_device.allocate(in.dimensions().TotalSize()*sizeof(DataType)));
  DataType* gpu_out_data = static_cast<DataType*>(sycl_device.allocate(redux_gpu.dimensions().TotalSize()*sizeof(DataType)));

  TensorMap<Tensor<DataType, 3, DataLayout> >  in_gpu(gpu_in_data, tensorRange);
  TensorMap<Tensor<DataType, 2, DataLayout> >  out_gpu(gpu_out_data, reduced_tensorRange);

  sycl_device.memcpyHostToDevice(gpu_in_data, in.data(),(in.dimensions().TotalSize())*sizeof(DataType));
  out_gpu.device(sycl_device) = in_gpu.sum(red_axis);
  sycl_device.memcpyDeviceToHost(redux_gpu.data(), gpu_out_data, redux_gpu.dimensions().TotalSize()*sizeof(DataType));

  // Check that the CPU and GPU reductions return the same result.
  for(int j=0; j<reduced_tensorRange[0]; j++ )
    for(int k=0; k<reduced_tensorRange[1]; k++ )
      VERIFY_IS_APPROX(redux_gpu(j,k), redux(j,k));

  sycl_device.deallocate(gpu_in_data);
  sycl_device.deallocate(gpu_out_data);
}

template <typename DataType, int DataLayout>
static void test_last_dim_reductions_sycl(const Eigen::SyclDevice &sycl_device) {

  int dim_x = 567;
  int dim_y = 1;
  int dim_z = 47;

  array<int, 3> tensorRange = {{dim_x, dim_y, dim_z}};
  Eigen::array<int, 1> red_axis;
  red_axis[0] = 2;
  array<int, 2> reduced_tensorRange = {{dim_x, dim_y}};

  Tensor<DataType, 3, DataLayout> in(tensorRange);
  Tensor<DataType, 2, DataLayout> redux(reduced_tensorRange);
  Tensor<DataType, 2, DataLayout> redux_gpu(reduced_tensorRange);

  in.setRandom();

  redux= in.sum(red_axis);

  DataType* gpu_in_data = static_cast<DataType*>(sycl_device.allocate(in.dimensions().TotalSize()*sizeof(DataType)));
  DataType* gpu_out_data = static_cast<DataType*>(sycl_device.allocate(redux_gpu.dimensions().TotalSize()*sizeof(DataType)));

  TensorMap<Tensor<DataType, 3, DataLayout> >  in_gpu(gpu_in_data, tensorRange);
  TensorMap<Tensor<DataType, 2, DataLayout> >  out_gpu(gpu_out_data, reduced_tensorRange);

  sycl_device.memcpyHostToDevice(gpu_in_data, in.data(),(in.dimensions().TotalSize())*sizeof(DataType));
  out_gpu.device(sycl_device) = in_gpu.sum(red_axis);
  sycl_device.memcpyDeviceToHost(redux_gpu.data(), gpu_out_data, redux_gpu.dimensions().TotalSize()*sizeof(DataType));
  // Check that the CPU and GPU reductions return the same result.
  for(int j=0; j<reduced_tensorRange[0]; j++ )
    for(int k=0; k<reduced_tensorRange[1]; k++ )
      VERIFY_IS_APPROX(redux_gpu(j,k), redux(j,k));

  sycl_device.deallocate(gpu_in_data);
  sycl_device.deallocate(gpu_out_data);

}
template<typename DataType> void sycl_reduction_test_per_device(const cl::sycl::device& d){
  std::cout << "Running on " << d.template get_info<cl::sycl::info::device::name>() << std::endl;
  QueueInterface queueInterface(d);
  auto sycl_device = Eigen::SyclDevice(&queueInterface);

  test_full_reductions_sycl<DataType, RowMajor>(sycl_device);
  test_first_dim_reductions_sycl<DataType, RowMajor>(sycl_device);
  test_last_dim_reductions_sycl<DataType, RowMajor>(sycl_device);
  test_full_reductions_sycl<DataType, ColMajor>(sycl_device);
  test_first_dim_reductions_sycl<DataType, ColMajor>(sycl_device);
  test_last_dim_reductions_sycl<DataType, ColMajor>(sycl_device);
}
void test_cxx11_tensor_reduction_sycl() {
  for (const auto& device : cl::sycl::device::get_devices()) {
    CALL_SUBTEST(sycl_reduction_test_per_device<float>(device));
  }
}
<|endoftext|>


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

#include "libheaptrack.h"

#include <link.h>
#include <string.h>
#include <stdlib.h>

/**
 * @file heaptrack_inject.cpp
 *
 * @brief Experimental support for symbol overloading after runtime injection.
 */

namespace {

namespace hooks {

struct malloc
{
    static constexpr auto name = "malloc";
    static constexpr auto original = &::malloc;
    using Signature = void* (*) (size_t);

    static void* hook(size_t size)
    {
        auto ptr = original(size);
        heaptrack_malloc(ptr, size);
        return ptr;
    }
};

struct free
{
    static constexpr auto name = "free";
    static constexpr auto original = &::free;
    using Signature = void (*) (void*);

    static void hook(void *ptr)
    {
        heaptrack_free(ptr);
        original(ptr);
    }
};

struct hook
{
    const char * const name;
    void* address;
};

const hook list[] = {
    {malloc::name, reinterpret_cast<void*>(&malloc::hook)},
    {free::name, reinterpret_cast<void*>(&free::hook)},
};

}

template<typename T, ElfW(Sxword) AddrTag, ElfW(Sxword) SizeTag>
struct elftable
{
    T* table = nullptr;
    ElfW(Xword) size = ElfW(Xword)();

    bool consume(const ElfW(Dyn) *dyn)
    {
        if (dyn->d_tag == AddrTag) {
            table = reinterpret_cast<T*>(dyn->d_un.d_ptr);
            return true;
        } else if (dyn->d_tag == SizeTag) {
            size = dyn->d_un.d_val;
            return true;
        }
        return false;
    }
};

using elf_string_table = elftable<const char, DT_STRTAB, DT_STRSZ>;
using elf_jmprel_table = elftable<ElfW(Rela), DT_JMPREL, DT_PLTRELSZ>;
using elf_symbol_table = elftable<ElfW(Sym), DT_SYMTAB, DT_SYMENT>;

void try_overwrite_symbols(const ElfW(Dyn) *dyn, const ElfW(Addr) base)
{
    elf_symbol_table symbols;
    elf_jmprel_table jmprels;
    elf_string_table strings;

    for (; dyn->d_tag != DT_NULL; ++dyn) {
        symbols.consume(dyn) || jmprels.consume(dyn) || strings.consume(dyn);
    }

    auto relaend = reinterpret_cast<ElfW(Rela) *>(reinterpret_cast<char *>(jmprels.table) + jmprels.size);
    for (auto rela = jmprels.table; rela < relaend; rela++) {
        auto relsymidx = ELF64_R_SYM(rela->r_info);
        const char *relsymname = strings.table + symbols.table[relsymidx].st_name;
        auto addr = reinterpret_cast<void**>(rela->r_offset + base);
        for (const auto& hook : hooks::list) {
            if (!strcmp(hook.name, relsymname)) {
                *addr = hook.address;
                break;
            }
        }
    }
}

int iterate_phdrs(dl_phdr_info *info, size_t /*size*/, void *data)
{
    if (strstr(info->dlpi_name, "/ld-linux-x86-64.so") || strstr(info->dlpi_name, "/libheaptrackinject.so")) {
        /// FIXME: why are these checks required? If I don't filter them out, we'll crash
        /// when trying to write the malloc symbols found
        return 0;
    }

    for (auto phdr = info->dlpi_phdr, end = phdr + info->dlpi_phnum; phdr != end; ++phdr) {
        if (phdr->p_type == PT_DYNAMIC && (phdr->p_flags & (PF_W | PF_R)) == (PF_W | PF_R)) {
            try_overwrite_symbols(reinterpret_cast<const ElfW(Dyn) *>(phdr->p_vaddr + info->dlpi_addr),
                                  info->dlpi_addr);
        }
    }
    return 0;
}

struct InitializeInjection
{
    InitializeInjection()
    {
        dl_iterate_phdr(&iterate_phdrs, nullptr);
        heaptrack_init();
    }
} initialize;

}
<commit_msg>Further cleanup the code<commit_after>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "libheaptrack.h"

#include <link.h>
#include <string.h>
#include <stdlib.h>

/**
 * @file heaptrack_inject.cpp
 *
 * @brief Experimental support for symbol overloading after runtime injection.
 */

namespace {

namespace hooks {

struct malloc
{
    static constexpr auto name = "malloc";
    static constexpr auto original = &::malloc;

    static void* hook(size_t size)
    {
        auto ptr = original(size);
        heaptrack_malloc(ptr, size);
        return ptr;
    }
};

struct free
{
    static constexpr auto name = "free";
    static constexpr auto original = &::free;

    static void hook(void *ptr)
    {
        heaptrack_free(ptr);
        original(ptr);
    }
};

struct hook
{
    const char * const name;
    void* address;

    template<typename Hook>
    static constexpr hook wrap()
    {
        static_assert(sizeof(&Hook::hook) == sizeof(void*), "Mismatched pointer sizes");
        // TODO: why is (void*) cast allowed, but not reinterpret_cast?
        return {Hook::name, (void*)(Hook::hook)};
    }
};

constexpr hook list[] = {
    hook::wrap<malloc>(),
    hook::wrap<free>()
};

}

template<typename T, ElfW(Sxword) AddrTag, ElfW(Sxword) SizeTag>
struct elftable
{
    T* table = nullptr;
    ElfW(Xword) size = ElfW(Xword)();

    bool consume(const ElfW(Dyn) *dyn)
    {
        if (dyn->d_tag == AddrTag) {
            table = reinterpret_cast<T*>(dyn->d_un.d_ptr);
            return true;
        } else if (dyn->d_tag == SizeTag) {
            size = dyn->d_un.d_val;
            return true;
        }
        return false;
    }
};

using elf_string_table = elftable<const char, DT_STRTAB, DT_STRSZ>;
using elf_jmprel_table = elftable<ElfW(Rela), DT_JMPREL, DT_PLTRELSZ>;
using elf_symbol_table = elftable<ElfW(Sym), DT_SYMTAB, DT_SYMENT>;

void try_overwrite_symbols(const ElfW(Dyn) *dyn, const ElfW(Addr) base)
{
    elf_symbol_table symbols;
    elf_jmprel_table jmprels;
    elf_string_table strings;

    for (; dyn->d_tag != DT_NULL; ++dyn) {
        symbols.consume(dyn) || jmprels.consume(dyn) || strings.consume(dyn);
    }

    auto relaend = reinterpret_cast<ElfW(Rela) *>(reinterpret_cast<char *>(jmprels.table) + jmprels.size);
    for (auto rela = jmprels.table; rela < relaend; rela++) {
        auto relsymidx = ELF64_R_SYM(rela->r_info);
        const char *relsymname = strings.table + symbols.table[relsymidx].st_name;
        auto addr = reinterpret_cast<void**>(rela->r_offset + base);
        for (const auto& hook : hooks::list) {
            if (!strcmp(hook.name, relsymname)) {
                *addr = hook.address;
                break;
            }
        }
    }
}

int iterate_phdrs(dl_phdr_info *info, size_t /*size*/, void *data)
{
    if (strstr(info->dlpi_name, "/ld-linux-x86-64.so") || strstr(info->dlpi_name, "/libheaptrackinject.so")) {
        /// FIXME: why are these checks required? If I don't filter them out, we'll crash
        /// when trying to write the malloc symbols found
        return 0;
    }

    for (auto phdr = info->dlpi_phdr, end = phdr + info->dlpi_phnum; phdr != end; ++phdr) {
        if (phdr->p_type == PT_DYNAMIC && (phdr->p_flags & (PF_W | PF_R)) == (PF_W | PF_R)) {
            try_overwrite_symbols(reinterpret_cast<const ElfW(Dyn) *>(phdr->p_vaddr + info->dlpi_addr),
                                  info->dlpi_addr);
        }
    }
    return 0;
}

struct InitializeInjection
{
    InitializeInjection()
    {
        dl_iterate_phdr(&iterate_phdrs, nullptr);
        heaptrack_init();
    }
} initialize;

}
<|endoftext|>


<commit_before>#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdexcept>
#include <fstream>
#include <xorg/gtest/xorg-gtest.h>

#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>

#include "input-driver-test.h"
#include "helpers.h"

#define TEST_TIMEOUT 60

static void sighandler_alarm(int signal)
{
    FAIL() << "Test has timed out (" << __func__ << "). Adjust TEST_TIMEOUT (" << TEST_TIMEOUT << "s) if needed.";
}

int InputDriverTest::RegisterXI2(int major, int minor)
{
    int event_start;
    int error_start;

    if (!XQueryExtension(Display(), "XInputExtension", &xi2_opcode,
                         &event_start, &error_start))
        ADD_FAILURE() << "XQueryExtension returned FALSE";

    int major_return = major;
    int minor_return = minor;
    if (XIQueryVersion(Display(), &major_return, &minor_return) != Success)
        ADD_FAILURE() << "XIQueryVersion failed";
    if (major_return != major)
       ADD_FAILURE() << "XIQueryVersion returned invalid major";

    return minor_return;
}

void InputDriverTest::StartServer() {
    /* No test takes longer than 60 seconds */
    alarm(60);
    signal(SIGALRM, sighandler_alarm);

    server.SetOption("-noreset", "");
    server.Start();
    xorg::testing::Test::SetDisplayString(server.GetDisplayString());

    ASSERT_NO_FATAL_FAILURE(xorg::testing::Test::SetUp());

    RegisterXI2();
}

void InputDriverTest::SetUpConfigAndLog(const std::string& param) {
    InitDefaultLogFiles(server, &config);

    config.AddDefaultScreenWithDriver();
    config.AddInputSection(param, "--device--", "Option \"CorePointer\" \"on\"\n");
    config.WriteConfig();
    server.SetOption("-config", config.GetPath());
}

void InputDriverTest::SetUpEventListener() {
    failed = false;

    testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
    listeners.Append(this);
}

void InputDriverTest::SetUp() {
    SetUp("");
}

void InputDriverTest::SetUp(const std::string &param) {
    SetUpEventListener();
    SetUpConfigAndLog(param);
    StartServer();
}

void InputDriverTest::TearDown() {
    alarm(0);
    if (server.Pid() != -1) {
        if (!server.Terminate(3000))
            server.Kill(3000);
        EXPECT_EQ(server.GetState(), xorg::testing::Process::FINISHED_SUCCESS) << "Unclean server shutdown";
        failed = (server.GetState() != xorg::testing::Process::FINISHED_SUCCESS);

        std::ifstream logfile(server.GetLogFilePath().c_str());
        std::string line;
        std::string bug_warn("BUG");
        if (logfile.is_open()) {
            while(getline(logfile, line)) {
                size_t found = line.find(bug_warn);
                bool error = (found != std::string::npos);
                EXPECT_FALSE(error) << "BUG warning found in log" << std::endl << line << std::endl;
                failed = failed || error;
                break;
            }
        }
    }

    if (!Failed()) {
        config.RemoveConfig();
        server.RemoveLogFile();
    }

    testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
    listeners.Release(this);
}

void InputDriverTest::OnTestPartResult(const ::testing::TestPartResult &test_part_result) {
    failed = test_part_result.failed();
}

bool InputDriverTest::Failed() {
    return failed;
}
<commit_msg>common: don't overwrite failed on success<commit_after>#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdexcept>
#include <fstream>
#include <xorg/gtest/xorg-gtest.h>

#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>

#include "input-driver-test.h"
#include "helpers.h"

#define TEST_TIMEOUT 60

static void sighandler_alarm(int signal)
{
    FAIL() << "Test has timed out (" << __func__ << "). Adjust TEST_TIMEOUT (" << TEST_TIMEOUT << "s) if needed.";
}

int InputDriverTest::RegisterXI2(int major, int minor)
{
    int event_start;
    int error_start;

    if (!XQueryExtension(Display(), "XInputExtension", &xi2_opcode,
                         &event_start, &error_start))
        ADD_FAILURE() << "XQueryExtension returned FALSE";

    int major_return = major;
    int minor_return = minor;
    if (XIQueryVersion(Display(), &major_return, &minor_return) != Success)
        ADD_FAILURE() << "XIQueryVersion failed";
    if (major_return != major)
       ADD_FAILURE() << "XIQueryVersion returned invalid major";

    return minor_return;
}

void InputDriverTest::StartServer() {
    /* No test takes longer than 60 seconds */
    alarm(60);
    signal(SIGALRM, sighandler_alarm);

    server.SetOption("-noreset", "");
    server.Start();
    xorg::testing::Test::SetDisplayString(server.GetDisplayString());

    ASSERT_NO_FATAL_FAILURE(xorg::testing::Test::SetUp());

    RegisterXI2();
}

void InputDriverTest::SetUpConfigAndLog(const std::string& param) {
    InitDefaultLogFiles(server, &config);

    config.AddDefaultScreenWithDriver();
    config.AddInputSection(param, "--device--", "Option \"CorePointer\" \"on\"\n");
    config.WriteConfig();
    server.SetOption("-config", config.GetPath());
}

void InputDriverTest::SetUpEventListener() {
    failed = false;

    testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
    listeners.Append(this);
}

void InputDriverTest::SetUp() {
    SetUp("");
}

void InputDriverTest::SetUp(const std::string &param) {
    SetUpEventListener();
    SetUpConfigAndLog(param);
    StartServer();
}

void InputDriverTest::TearDown() {
    alarm(0);
    if (server.Pid() != -1) {
        if (!server.Terminate(3000))
            server.Kill(3000);
        EXPECT_EQ(server.GetState(), xorg::testing::Process::FINISHED_SUCCESS) << "Unclean server shutdown";
        failed = failed || (server.GetState() != xorg::testing::Process::FINISHED_SUCCESS);

        std::ifstream logfile(server.GetLogFilePath().c_str());
        std::string line;
        std::string bug_warn("BUG");
        if (logfile.is_open()) {
            while(getline(logfile, line)) {
                size_t found = line.find(bug_warn);
                bool error = (found != std::string::npos);
                EXPECT_FALSE(error) << "BUG warning found in log" << std::endl << line << std::endl;
                failed = failed || error;
                break;
            }
        }
    }

    if (!Failed()) {
        config.RemoveConfig();
        server.RemoveLogFile();
    }

    testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners();
    listeners.Release(this);
}

void InputDriverTest::OnTestPartResult(const ::testing::TestPartResult &test_part_result) {
    failed = failed || test_part_result.failed();
}

bool InputDriverTest::Failed() {
    return failed;
}
<|endoftext|>


<commit_before><commit_msg>Remove a DCHECK which is being hit because of a unit-test's particular setup.<commit_after><|endoftext|>


<commit_before><commit_msg>Try to fix build bustage.<commit_after><|endoftext|>


<commit_before><commit_msg>Benchmark memcpy of the output of OpenMAX decoder<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/controls/message_box_view.h"

#include "base/i18n/rtl.h"
#include "base/message_loop.h"
#include "base/string_split.h"
#include "base/utf_string_conversions.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/layout/layout_constants.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/client_view.h"

namespace {

const int kDefaultMessageWidth = 320;

// Paragraph separators are defined in
// http://www.unicode.org/Public/6.0.0/ucd/extracted/DerivedBidiClass.txt
//
// # Bidi_Class=Paragraph_Separator
//
// 000A          ; B # Cc       <control-000A>
// 000D          ; B # Cc       <control-000D>
// 001C..001E    ; B # Cc   [3] <control-001C>..<control-001E>
// 0085          ; B # Cc       <control-0085>
// 2029          ; B # Zp       PARAGRAPH SEPARATOR
bool IsParagraphSeparator(char16 c) {
  return ( c == 0x000A || c == 0x000D || c == 0x001C || c == 0x001D ||
           c == 0x001E || c == 0x0085 || c == 0x2029);
}

// Splits |text| into a vector of paragraphs.
// Given an example "\nabc\ndef\n\n\nhij\n", the split results should be:
// "", "abc", "def", "", "", "hij", and "".
void SplitStringIntoParagraphs(const string16& text,
                               std::vector<string16>* paragraphs) {
  paragraphs->clear();

  size_t start = 0;
  for (size_t i = 0; i < text.length(); ++i) {
    if (IsParagraphSeparator(text[i])) {
      paragraphs->push_back(text.substr(start, i - start));
      start = i + 1;
    }
  }
  paragraphs->push_back(text.substr(start, text.length() - start));
}

}  // namespace

namespace views {

///////////////////////////////////////////////////////////////////////////////
// MessageBoxView, public:

MessageBoxView::InitParams::InitParams(const string16& message)
    : options(NO_OPTIONS),
      message(message),
      message_width(kDefaultMessageWidth) {
}

MessageBoxView::InitParams::~InitParams() {
}

MessageBoxView::MessageBoxView(const InitParams& params)
    : prompt_field_(NULL),
      icon_(NULL),
      checkbox_(NULL),
      message_width_(params.message_width) {
  Init(params);
}

MessageBoxView::~MessageBoxView() {}

string16 MessageBoxView::GetInputText() {
  return prompt_field_ ? prompt_field_->text() : string16();
}

bool MessageBoxView::IsCheckBoxSelected() {
  return checkbox_ ? checkbox_->checked() : false;
}

void MessageBoxView::SetIcon(const SkBitmap& icon) {
  if (!icon_)
    icon_ = new ImageView();
  icon_->SetImage(icon);
  icon_->SetBounds(0, 0, icon.width(), icon.height());
  ResetLayoutManager();
}

void MessageBoxView::SetCheckBoxLabel(const string16& label) {
  if (!checkbox_)
    checkbox_ = new Checkbox(label);
  else
    checkbox_->SetText(label);
  ResetLayoutManager();
}

void MessageBoxView::SetCheckBoxSelected(bool selected) {
  if (!checkbox_)
    return;
  checkbox_->SetChecked(selected);
}

void MessageBoxView::GetAccessibleState(ui::AccessibleViewState* state) {
  state->role = ui::AccessibilityTypes::ROLE_ALERT;
}

///////////////////////////////////////////////////////////////////////////////
// MessageBoxView, View overrides:

void MessageBoxView::ViewHierarchyChanged(bool is_add,
                                          View* parent,
                                          View* child) {
  if (child == this && is_add) {
    if (prompt_field_)
      prompt_field_->SelectAll();

    GetWidget()->NotifyAccessibilityEvent(
        this, ui::AccessibilityTypes::EVENT_ALERT, true);
  }
}

bool MessageBoxView::AcceleratorPressed(const ui::Accelerator& accelerator) {
  // We only accepts Ctrl-C.
  DCHECK(accelerator.key_code() == 'C' && accelerator.IsCtrlDown());

  // We must not intercept Ctrl-C when we have a text box and it's focused.
  if (prompt_field_ && prompt_field_->HasFocus())
    return false;

  if (!ViewsDelegate::views_delegate)
    return false;

  ui::Clipboard* clipboard = ViewsDelegate::views_delegate->GetClipboard();
  if (!clipboard)
    return false;

  ui::ScopedClipboardWriter scw(clipboard, ui::Clipboard::BUFFER_STANDARD);
  string16 text = message_labels_[0]->text();
  for (size_t i = 1; i < message_labels_.size(); ++i)
    text += message_labels_[i]->text();
  scw.WriteText(text);
  return true;
}

///////////////////////////////////////////////////////////////////////////////
// MessageBoxView, private:

void MessageBoxView::Init(const InitParams& params) {
  if (params.options & DETECT_DIRECTIONALITY) {
    std::vector<string16> texts;
    SplitStringIntoParagraphs(params.message, &texts);
    // If the text originates from a web page, its alignment is based on its
    // first character with strong directionality.
    base::i18n::TextDirection message_direction =
        base::i18n::GetFirstStrongCharacterDirection(params.message);
    Label::Alignment alignment =
        (message_direction == base::i18n::RIGHT_TO_LEFT) ?
        Label::ALIGN_RIGHT : Label::ALIGN_LEFT;
    for (size_t i = 0; i < texts.size(); ++i) {
      Label* message_label = new Label(texts[i]);
      message_label->SetMultiLine(true);
      message_label->SetAllowCharacterBreak(true);
      message_label->set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
      message_label->SetHorizontalAlignment(alignment);
      message_labels_.push_back(message_label);
    }
  } else {
    Label* message_label = new Label(params.message);
    message_label->SetMultiLine(true);
    message_label->SetAllowCharacterBreak(true);
    message_label->SetHorizontalAlignment(Label::ALIGN_LEFT);
    message_labels_.push_back(message_label);
  }

  if (params.options & HAS_PROMPT_FIELD) {
    prompt_field_ = new Textfield;
    prompt_field_->SetText(params.default_prompt);
  }

  ResetLayoutManager();
}

void MessageBoxView::ResetLayoutManager() {
  // Initialize the Grid Layout Manager used for this dialog box.
  GridLayout* layout = GridLayout::CreatePanel(this);
  SetLayoutManager(layout);

  gfx::Size icon_size;
  if (icon_)
    icon_size = icon_->GetPreferredSize();

  // Add the column set for the message displayed at the top of the dialog box.
  // And an icon, if one has been set.
  const int message_column_view_set_id = 0;
  ColumnSet* column_set = layout->AddColumnSet(message_column_view_set_id);
  if (icon_) {
    column_set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
                          GridLayout::FIXED, icon_size.width(),
                          icon_size.height());
    column_set->AddPaddingColumn(0, kUnrelatedControlHorizontalSpacing);
  }
  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                        GridLayout::FIXED, message_width_, 0);

  // Column set for prompt Textfield, if one has been set.
  const int textfield_column_view_set_id = 1;
  if (prompt_field_) {
    column_set = layout->AddColumnSet(textfield_column_view_set_id);
    if (icon_) {
      column_set->AddPaddingColumn(
          0, icon_size.width() + kUnrelatedControlHorizontalSpacing);
    }
    column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                          GridLayout::USE_PREF, 0, 0);
  }

  // Column set for checkbox, if one has been set.
  const int checkbox_column_view_set_id = 2;
  if (checkbox_) {
    column_set = layout->AddColumnSet(checkbox_column_view_set_id);
    if (icon_) {
      column_set->AddPaddingColumn(
          0, icon_size.width() + kUnrelatedControlHorizontalSpacing);
    }
    column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                          GridLayout::USE_PREF, 0, 0);
  }

  for (size_t i = 0; i < message_labels_.size(); ++i) {
    layout->StartRow(i, message_column_view_set_id);
    if (icon_) {
      if (i == 0)
        layout->AddView(icon_);
      else
        layout->SkipColumns(1);
    }
    layout->AddView(message_labels_[i]);
  }

  if (prompt_field_) {
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
    layout->StartRow(0, textfield_column_view_set_id);
    layout->AddView(prompt_field_);
  }

  if (checkbox_) {
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
    layout->StartRow(0, checkbox_column_view_set_id);
    layout->AddView(checkbox_);
  }

  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
}

}  // namespace views
<commit_msg>Fix blank lines being ignored in JS alerts.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/controls/message_box_view.h"

#include "base/i18n/rtl.h"
#include "base/message_loop.h"
#include "base/string_split.h"
#include "base/utf_string_conversions.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/layout/layout_constants.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/client_view.h"

namespace {

const int kDefaultMessageWidth = 320;

// Paragraph separators are defined in
// http://www.unicode.org/Public/6.0.0/ucd/extracted/DerivedBidiClass.txt
//
// # Bidi_Class=Paragraph_Separator
//
// 000A          ; B # Cc       <control-000A>
// 000D          ; B # Cc       <control-000D>
// 001C..001E    ; B # Cc   [3] <control-001C>..<control-001E>
// 0085          ; B # Cc       <control-0085>
// 2029          ; B # Zp       PARAGRAPH SEPARATOR
bool IsParagraphSeparator(char16 c) {
  return ( c == 0x000A || c == 0x000D || c == 0x001C || c == 0x001D ||
           c == 0x001E || c == 0x0085 || c == 0x2029);
}

// Splits |text| into a vector of paragraphs.
// Given an example "\nabc\ndef\n\n\nhij\n", the split results should be:
// "", "abc", "def", "", "", "hij", and "".
void SplitStringIntoParagraphs(const string16& text,
                               std::vector<string16>* paragraphs) {
  paragraphs->clear();

  size_t start = 0;
  for (size_t i = 0; i < text.length(); ++i) {
    if (IsParagraphSeparator(text[i])) {
      paragraphs->push_back(text.substr(start, i - start));
      start = i + 1;
    }
  }
  paragraphs->push_back(text.substr(start, text.length() - start));
}

}  // namespace

namespace views {

///////////////////////////////////////////////////////////////////////////////
// MessageBoxView, public:

MessageBoxView::InitParams::InitParams(const string16& message)
    : options(NO_OPTIONS),
      message(message),
      message_width(kDefaultMessageWidth) {
}

MessageBoxView::InitParams::~InitParams() {
}

MessageBoxView::MessageBoxView(const InitParams& params)
    : prompt_field_(NULL),
      icon_(NULL),
      checkbox_(NULL),
      message_width_(params.message_width) {
  Init(params);
}

MessageBoxView::~MessageBoxView() {}

string16 MessageBoxView::GetInputText() {
  return prompt_field_ ? prompt_field_->text() : string16();
}

bool MessageBoxView::IsCheckBoxSelected() {
  return checkbox_ ? checkbox_->checked() : false;
}

void MessageBoxView::SetIcon(const SkBitmap& icon) {
  if (!icon_)
    icon_ = new ImageView();
  icon_->SetImage(icon);
  icon_->SetBounds(0, 0, icon.width(), icon.height());
  ResetLayoutManager();
}

void MessageBoxView::SetCheckBoxLabel(const string16& label) {
  if (!checkbox_)
    checkbox_ = new Checkbox(label);
  else
    checkbox_->SetText(label);
  ResetLayoutManager();
}

void MessageBoxView::SetCheckBoxSelected(bool selected) {
  if (!checkbox_)
    return;
  checkbox_->SetChecked(selected);
}

void MessageBoxView::GetAccessibleState(ui::AccessibleViewState* state) {
  state->role = ui::AccessibilityTypes::ROLE_ALERT;
}

///////////////////////////////////////////////////////////////////////////////
// MessageBoxView, View overrides:

void MessageBoxView::ViewHierarchyChanged(bool is_add,
                                          View* parent,
                                          View* child) {
  if (child == this && is_add) {
    if (prompt_field_)
      prompt_field_->SelectAll();

    GetWidget()->NotifyAccessibilityEvent(
        this, ui::AccessibilityTypes::EVENT_ALERT, true);
  }
}

bool MessageBoxView::AcceleratorPressed(const ui::Accelerator& accelerator) {
  // We only accepts Ctrl-C.
  DCHECK(accelerator.key_code() == 'C' && accelerator.IsCtrlDown());

  // We must not intercept Ctrl-C when we have a text box and it's focused.
  if (prompt_field_ && prompt_field_->HasFocus())
    return false;

  if (!ViewsDelegate::views_delegate)
    return false;

  ui::Clipboard* clipboard = ViewsDelegate::views_delegate->GetClipboard();
  if (!clipboard)
    return false;

  ui::ScopedClipboardWriter scw(clipboard, ui::Clipboard::BUFFER_STANDARD);
  string16 text = message_labels_[0]->text();
  for (size_t i = 1; i < message_labels_.size(); ++i)
    text += message_labels_[i]->text();
  scw.WriteText(text);
  return true;
}

///////////////////////////////////////////////////////////////////////////////
// MessageBoxView, private:

void MessageBoxView::Init(const InitParams& params) {
  if (params.options & DETECT_DIRECTIONALITY) {
    std::vector<string16> texts;
    SplitStringIntoParagraphs(params.message, &texts);
    // If the text originates from a web page, its alignment is based on its
    // first character with strong directionality.
    base::i18n::TextDirection message_direction =
        base::i18n::GetFirstStrongCharacterDirection(params.message);
    Label::Alignment alignment =
        (message_direction == base::i18n::RIGHT_TO_LEFT) ?
        Label::ALIGN_RIGHT : Label::ALIGN_LEFT;
    for (size_t i = 0; i < texts.size(); ++i) {
      Label* message_label = new Label(texts[i]);
      // Don't set multi-line to true if the text is empty, else the label will
      // have a height of 0.
      message_label->SetMultiLine(!texts[i].empty());
      message_label->SetAllowCharacterBreak(true);
      message_label->set_directionality_mode(Label::AUTO_DETECT_DIRECTIONALITY);
      message_label->SetHorizontalAlignment(alignment);
      message_labels_.push_back(message_label);
    }
  } else {
    Label* message_label = new Label(params.message);
    message_label->SetMultiLine(true);
    message_label->SetAllowCharacterBreak(true);
    message_label->SetHorizontalAlignment(Label::ALIGN_LEFT);
    message_labels_.push_back(message_label);
  }

  if (params.options & HAS_PROMPT_FIELD) {
    prompt_field_ = new Textfield;
    prompt_field_->SetText(params.default_prompt);
  }

  ResetLayoutManager();
}

void MessageBoxView::ResetLayoutManager() {
  // Initialize the Grid Layout Manager used for this dialog box.
  GridLayout* layout = GridLayout::CreatePanel(this);
  SetLayoutManager(layout);

  gfx::Size icon_size;
  if (icon_)
    icon_size = icon_->GetPreferredSize();

  // Add the column set for the message displayed at the top of the dialog box.
  // And an icon, if one has been set.
  const int message_column_view_set_id = 0;
  ColumnSet* column_set = layout->AddColumnSet(message_column_view_set_id);
  if (icon_) {
    column_set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
                          GridLayout::FIXED, icon_size.width(),
                          icon_size.height());
    column_set->AddPaddingColumn(0, kUnrelatedControlHorizontalSpacing);
  }
  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                        GridLayout::FIXED, message_width_, 0);

  // Column set for prompt Textfield, if one has been set.
  const int textfield_column_view_set_id = 1;
  if (prompt_field_) {
    column_set = layout->AddColumnSet(textfield_column_view_set_id);
    if (icon_) {
      column_set->AddPaddingColumn(
          0, icon_size.width() + kUnrelatedControlHorizontalSpacing);
    }
    column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                          GridLayout::USE_PREF, 0, 0);
  }

  // Column set for checkbox, if one has been set.
  const int checkbox_column_view_set_id = 2;
  if (checkbox_) {
    column_set = layout->AddColumnSet(checkbox_column_view_set_id);
    if (icon_) {
      column_set->AddPaddingColumn(
          0, icon_size.width() + kUnrelatedControlHorizontalSpacing);
    }
    column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                          GridLayout::USE_PREF, 0, 0);
  }

  for (size_t i = 0; i < message_labels_.size(); ++i) {
    layout->StartRow(i, message_column_view_set_id);
    if (icon_) {
      if (i == 0)
        layout->AddView(icon_);
      else
        layout->SkipColumns(1);
    }
    layout->AddView(message_labels_[i]);
  }

  if (prompt_field_) {
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
    layout->StartRow(0, textfield_column_view_set_id);
    layout->AddView(prompt_field_);
  }

  if (checkbox_) {
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
    layout->StartRow(0, checkbox_column_view_set_id);
    layout->AddView(checkbox_);
  }

  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
}

}  // namespace views
<|endoftext|>


<commit_before>#if _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#define WIN_PAUSE 0
#include <objbase.h>
#endif

#include <clocale>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cstdarg>
#include <signal.h>
#include <regex>
#include <list>
#include "hecl/Database.hpp"
#include "hecl/Blender/Connection.hpp"
#include "logvisor/logvisor.hpp"

logvisor::Module LogModule("hecl::Driver");

#include "ToolBase.hpp"
#include "ToolInit.hpp"
#include "ToolSpec.hpp"
#include "ToolExtract.hpp"
#include "ToolCook.hpp"
#include "ToolPackage.hpp"
#include "ToolImage.hpp"
#include "ToolHelp.hpp"

/* Static reference to dataspec additions
 * (used by MSVC to definitively link DataSpecs) */
#include "DataSpecRegistry.hpp"

bool XTERM_COLOR = false;

/*
#define HECL_GIT 1234567
#define HECL_GIT_S "1234567"
#define HECL_BRANCH master
#define HECL_BRANCH_S "master"
*/

/* Main usage message */
static void printHelp(const hecl::SystemChar* pname) {
  if (XTERM_COLOR)
    fmt::print(fmt(_SYS_STR("" BOLD "HECL" NORMAL "")));
  else
    fmt::print(fmt(_SYS_STR("HECL")));
#if HECL_HAS_NOD
#define TOOL_LIST "extract|init|cook|package|image|help"
#else
#define TOOL_LIST "extract|init|cook|package|help"
#endif
#if HECL_GIT
  fmt::print(fmt(_SYS_STR(" Commit " HECL_GIT_S " " HECL_BRANCH_S "\nUsage: {} " TOOL_LIST "\n")), pname);
#elif HECL_VER
  fmt::print(fmt(_SYS_STR(" Version " HECL_VER_S "\nUsage: {} " TOOL_LIST "\n")), pname);
#else
  fmt::print(fmt(_SYS_STR("\nUsage: {} " TOOL_LIST "\n")), pname);
#endif
}

/* Regex patterns */
static const hecl::SystemRegex regOPEN(_SYS_STR("-o([^\"]*|\\S*)"), std::regex::ECMAScript | std::regex::optimize);

static ToolBase* ToolPtr = nullptr;

/* SIGINT will gracefully close blender connections and delete blends in progress */
static void SIGINTHandler(int sig) {
  if (ToolPtr)
    ToolPtr->cancel();
  hecl::blender::Connection::Shutdown();
  logvisor::KillProcessTree();
  exit(1);
}

static logvisor::Module AthenaLog("Athena");
static void AthenaExc(athena::error::Level level, const char* file, const char*, int line, fmt::string_view fmt,
                      fmt::format_args args) {
  AthenaLog.vreport(logvisor::Level(level), fmt, args);
}

hecl::SystemString ExeDir;

#if _WIN32
static ToolPassInfo CreateInfo(int argc, const wchar_t** argv) {
#else
static ToolPassInfo CreateInfo(int argc, const char** argv) {
#endif
  hecl::SystemChar cwdbuf[1024];

  ToolPassInfo info;
  info.pname = argv[0];

  if (hecl::Getcwd(cwdbuf, static_cast<int>(std::size(cwdbuf)))) {
    info.cwd = cwdbuf;
    if (info.cwd.size() && info.cwd.back() != _SYS_STR('/') && info.cwd.back() != _SYS_STR('\\')) {
#if _WIN32
      info.cwd += _SYS_STR('\\');
#else
      info.cwd += _SYS_STR('/');
#endif
    }

    if (hecl::PathRelative(argv[0])) {
      ExeDir = hecl::SystemString(cwdbuf) + _SYS_STR('/');
    }
    hecl::SystemString Argv0(argv[0]);
    hecl::SystemString::size_type lastIdx = Argv0.find_last_of(_SYS_STR("/\\"));
    if (lastIdx != hecl::SystemString::npos) {
      ExeDir.insert(ExeDir.end(), Argv0.begin(), Argv0.begin() + lastIdx);
    }
  }

  /* Concatenate args */
  std::vector<hecl::SystemString> args;
  args.reserve(argc - 2);
  for (int i = 2; i < argc; ++i) {
    args.emplace_back(argv[i]);
  }

  if (!args.empty()) {
    /* Extract output argument */
    for (auto it = args.cbegin(); it != args.cend();) {
      const hecl::SystemString& arg = *it;
      hecl::SystemRegexMatch oMatch;

      if (std::regex_search(arg, oMatch, regOPEN)) {
        const hecl::SystemString& token = oMatch[1].str();

        if (token.size()) {
          if (info.output.empty()) {
            info.output = oMatch[1].str();
          }

          it = args.erase(it);
        } else {
          it = args.erase(it);

          if (it == args.end()) {
            break;
          }

          if (info.output.empty()) {
            info.output = *it;
          }

          it = args.erase(it);
        }

        continue;
      }

      ++it;
    }

    /* Iterate flags */
    bool threadArg = false;
    for (auto it = args.cbegin(); it != args.cend();) {
      const hecl::SystemString& arg = *it;
      if (threadArg) {
        threadArg = false;
        hecl::CpuCountOverride = int(hecl::StrToUl(arg.c_str(), nullptr, 0));
        it = args.erase(it);
        continue;
      }
      if (arg.size() < 2 || arg[0] != _SYS_STR('-') || arg[1] == _SYS_STR('-')) {
        ++it;
        continue;
      }

      for (auto chit = arg.cbegin() + 1; chit != arg.cend(); ++chit) {
        if (*chit == _SYS_STR('v'))
          ++info.verbosityLevel;
        else if (*chit == _SYS_STR('f'))
          info.force = true;
        else if (*chit == _SYS_STR('y'))
          info.yes = true;
        else if (*chit == _SYS_STR('g'))
          info.gui = true;
        else if (*chit == _SYS_STR('j')) {
          ++chit;
          if (*chit)
            hecl::CpuCountOverride = int(hecl::StrToUl(&*chit, nullptr, 0));
          else
            threadArg = true;
          break;
        } else
          info.flags.push_back(*chit);
      }

      it = args.erase(it);
    }

    /* Gather remaining args */
    info.args.reserve(args.size());
    for (const hecl::SystemString& arg : args)
      info.args.push_back(arg);
  }

  return info;
}

static std::unique_ptr<hecl::Database::Project> FindProject(hecl::SystemStringView cwd) {
  const hecl::ProjectRootPath rootPath = hecl::SearchForProject(cwd);
  if (!rootPath) {
    return nullptr;
  }

  const size_t ErrorRef = logvisor::ErrorCount;
  auto newProj = std::make_unique<hecl::Database::Project>(rootPath);
  if (logvisor::ErrorCount > ErrorRef) {
#if WIN_PAUSE
    system("PAUSE");
#endif
    return nullptr;
  }

  return newProj;
}

static std::unique_ptr<ToolBase> MakeSelectedTool(hecl::SystemString toolName, ToolPassInfo& info) {
  hecl::SystemString toolNameLower = toolName;
  hecl::ToLower(toolNameLower);

  if (toolNameLower == _SYS_STR("init")) {
    return std::make_unique<ToolInit>(info);
  }

  if (toolNameLower == _SYS_STR("spec")) {
    return std::make_unique<ToolSpec>(info);
  }

  if (toolNameLower == _SYS_STR("extract")) {
    return std::make_unique<ToolExtract>(info);
  }

  if (toolNameLower == _SYS_STR("cook")) {
    return std::make_unique<ToolCook>(info);
  }

  if (toolNameLower == _SYS_STR("package") || toolNameLower == _SYS_STR("pack")) {
    return std::make_unique<ToolPackage>(info);
  }

#if HECL_HAS_NOD
  if (toolNameLower == _SYS_STR("image")) {
    return std::make_unique<ToolImage>(info);
  }
#endif

  if (toolNameLower == _SYS_STR("help")) {
    return std::make_unique<ToolHelp>(info);
  }

  std::unique_ptr<FILE, decltype(&std::fclose)> fp{hecl::Fopen(toolName.c_str(), _SYS_STR("rb")), std::fclose};
  if (fp == nullptr) {
    LogModule.report(logvisor::Error, fmt(_SYS_STR("unrecognized tool '{}'")), toolNameLower);
    return nullptr;
  }
  fp.reset();

  /* Shortcut-case: implicit extract */
  info.args.insert(info.args.begin(), std::move(toolName));
  return std::make_unique<ToolExtract>(info);
}

#if _WIN32
int wmain(int argc, const wchar_t** argv)
#else
/* SIGWINCH should do nothing */
static void SIGWINCHHandler(int sig) {}
int main(int argc, const char** argv)
#endif
{
  if (argc > 1 && !hecl::StrCmp(argv[1], _SYS_STR("--dlpackage"))) {
    fmt::print(fmt("{}\n"), HECL_DLPACKAGE);
    return 100;
  }

#if _WIN32
  CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
#else
  std::setlocale(LC_ALL, "en-US.UTF-8");
#endif

  /* Xterm check */
#if _WIN32
  const char* conemuANSI = getenv("ConEmuANSI");
  if (conemuANSI && !strcmp(conemuANSI, "ON"))
    XTERM_COLOR = true;
#else
  const char* term = getenv("TERM");
  if (term && !strncmp(term, "xterm", 5))
    XTERM_COLOR = true;
  signal(SIGWINCH, SIGWINCHHandler);
#endif
  signal(SIGINT, SIGINTHandler);

  logvisor::RegisterStandardExceptions();
  logvisor::RegisterConsoleLogger();
  atSetExceptionHandler(AthenaExc);

  /* Basic usage check */
  if (argc == 1) {
    printHelp(argv[0]);
#if WIN_PAUSE
    system("PAUSE");
#endif
    return 0;
  } else if (argc == 0) {
    printHelp(_SYS_STR("hecl"));
#if WIN_PAUSE
    system("PAUSE");
#endif
    return 0;
  }

  /* Prepare DataSpecs */
  HECLRegisterDataSpecs();

  /* Assemble common tool pass info */
  ToolPassInfo info = CreateInfo(argc, argv);

  /* Attempt to find hecl project */
  auto project = FindProject(info.cwd);
  if (project != nullptr) {
    info.project = project.get();
  }

  /* Construct selected tool */
  size_t ErrorRef = logvisor::ErrorCount;
  auto tool = MakeSelectedTool(argv[1], info);

  if (logvisor::ErrorCount > ErrorRef) {
#if WIN_PAUSE
    system("PAUSE");
#endif
    return 1;
  }

  if (info.verbosityLevel) {
    LogModule.report(logvisor::Info, fmt(_SYS_STR("Constructed tool '{}' {}\n")), tool->toolName(),
                     info.verbosityLevel);
  }

  /* Run tool */
  ErrorRef = logvisor::ErrorCount;
  ToolPtr = tool.get();
  int retval = tool->run();
  ToolPtr = nullptr;
  if (logvisor::ErrorCount > ErrorRef) {
    hecl::blender::Connection::Shutdown();
#if WIN_PAUSE
    system("PAUSE");
#endif
    return 1;
  }

  hecl::blender::Connection::Shutdown();
#if WIN_PAUSE
  system("PAUSE");
#endif
  return retval;
}
<commit_msg>driver/main: Use separate variables for error checking in main()<commit_after>#if _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#define WIN_PAUSE 0
#include <objbase.h>
#endif

#include <clocale>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cstdarg>
#include <signal.h>
#include <regex>
#include <list>
#include "hecl/Database.hpp"
#include "hecl/Blender/Connection.hpp"
#include "logvisor/logvisor.hpp"

logvisor::Module LogModule("hecl::Driver");

#include "ToolBase.hpp"
#include "ToolInit.hpp"
#include "ToolSpec.hpp"
#include "ToolExtract.hpp"
#include "ToolCook.hpp"
#include "ToolPackage.hpp"
#include "ToolImage.hpp"
#include "ToolHelp.hpp"

/* Static reference to dataspec additions
 * (used by MSVC to definitively link DataSpecs) */
#include "DataSpecRegistry.hpp"

bool XTERM_COLOR = false;

/*
#define HECL_GIT 1234567
#define HECL_GIT_S "1234567"
#define HECL_BRANCH master
#define HECL_BRANCH_S "master"
*/

/* Main usage message */
static void printHelp(const hecl::SystemChar* pname) {
  if (XTERM_COLOR)
    fmt::print(fmt(_SYS_STR("" BOLD "HECL" NORMAL "")));
  else
    fmt::print(fmt(_SYS_STR("HECL")));
#if HECL_HAS_NOD
#define TOOL_LIST "extract|init|cook|package|image|help"
#else
#define TOOL_LIST "extract|init|cook|package|help"
#endif
#if HECL_GIT
  fmt::print(fmt(_SYS_STR(" Commit " HECL_GIT_S " " HECL_BRANCH_S "\nUsage: {} " TOOL_LIST "\n")), pname);
#elif HECL_VER
  fmt::print(fmt(_SYS_STR(" Version " HECL_VER_S "\nUsage: {} " TOOL_LIST "\n")), pname);
#else
  fmt::print(fmt(_SYS_STR("\nUsage: {} " TOOL_LIST "\n")), pname);
#endif
}

/* Regex patterns */
static const hecl::SystemRegex regOPEN(_SYS_STR("-o([^\"]*|\\S*)"), std::regex::ECMAScript | std::regex::optimize);

static ToolBase* ToolPtr = nullptr;

/* SIGINT will gracefully close blender connections and delete blends in progress */
static void SIGINTHandler(int sig) {
  if (ToolPtr)
    ToolPtr->cancel();
  hecl::blender::Connection::Shutdown();
  logvisor::KillProcessTree();
  exit(1);
}

static logvisor::Module AthenaLog("Athena");
static void AthenaExc(athena::error::Level level, const char* file, const char*, int line, fmt::string_view fmt,
                      fmt::format_args args) {
  AthenaLog.vreport(logvisor::Level(level), fmt, args);
}

hecl::SystemString ExeDir;

#if _WIN32
static ToolPassInfo CreateInfo(int argc, const wchar_t** argv) {
#else
static ToolPassInfo CreateInfo(int argc, const char** argv) {
#endif
  hecl::SystemChar cwdbuf[1024];

  ToolPassInfo info;
  info.pname = argv[0];

  if (hecl::Getcwd(cwdbuf, static_cast<int>(std::size(cwdbuf)))) {
    info.cwd = cwdbuf;
    if (info.cwd.size() && info.cwd.back() != _SYS_STR('/') && info.cwd.back() != _SYS_STR('\\')) {
#if _WIN32
      info.cwd += _SYS_STR('\\');
#else
      info.cwd += _SYS_STR('/');
#endif
    }

    if (hecl::PathRelative(argv[0])) {
      ExeDir = hecl::SystemString(cwdbuf) + _SYS_STR('/');
    }
    hecl::SystemString Argv0(argv[0]);
    hecl::SystemString::size_type lastIdx = Argv0.find_last_of(_SYS_STR("/\\"));
    if (lastIdx != hecl::SystemString::npos) {
      ExeDir.insert(ExeDir.end(), Argv0.begin(), Argv0.begin() + lastIdx);
    }
  }

  /* Concatenate args */
  std::vector<hecl::SystemString> args;
  args.reserve(argc - 2);
  for (int i = 2; i < argc; ++i) {
    args.emplace_back(argv[i]);
  }

  if (!args.empty()) {
    /* Extract output argument */
    for (auto it = args.cbegin(); it != args.cend();) {
      const hecl::SystemString& arg = *it;
      hecl::SystemRegexMatch oMatch;

      if (std::regex_search(arg, oMatch, regOPEN)) {
        const hecl::SystemString& token = oMatch[1].str();

        if (token.size()) {
          if (info.output.empty()) {
            info.output = oMatch[1].str();
          }

          it = args.erase(it);
        } else {
          it = args.erase(it);

          if (it == args.end()) {
            break;
          }

          if (info.output.empty()) {
            info.output = *it;
          }

          it = args.erase(it);
        }

        continue;
      }

      ++it;
    }

    /* Iterate flags */
    bool threadArg = false;
    for (auto it = args.cbegin(); it != args.cend();) {
      const hecl::SystemString& arg = *it;
      if (threadArg) {
        threadArg = false;
        hecl::CpuCountOverride = int(hecl::StrToUl(arg.c_str(), nullptr, 0));
        it = args.erase(it);
        continue;
      }
      if (arg.size() < 2 || arg[0] != _SYS_STR('-') || arg[1] == _SYS_STR('-')) {
        ++it;
        continue;
      }

      for (auto chit = arg.cbegin() + 1; chit != arg.cend(); ++chit) {
        if (*chit == _SYS_STR('v'))
          ++info.verbosityLevel;
        else if (*chit == _SYS_STR('f'))
          info.force = true;
        else if (*chit == _SYS_STR('y'))
          info.yes = true;
        else if (*chit == _SYS_STR('g'))
          info.gui = true;
        else if (*chit == _SYS_STR('j')) {
          ++chit;
          if (*chit)
            hecl::CpuCountOverride = int(hecl::StrToUl(&*chit, nullptr, 0));
          else
            threadArg = true;
          break;
        } else
          info.flags.push_back(*chit);
      }

      it = args.erase(it);
    }

    /* Gather remaining args */
    info.args.reserve(args.size());
    for (const hecl::SystemString& arg : args)
      info.args.push_back(arg);
  }

  return info;
}

static std::unique_ptr<hecl::Database::Project> FindProject(hecl::SystemStringView cwd) {
  const hecl::ProjectRootPath rootPath = hecl::SearchForProject(cwd);
  if (!rootPath) {
    return nullptr;
  }

  const size_t ErrorRef = logvisor::ErrorCount;
  auto newProj = std::make_unique<hecl::Database::Project>(rootPath);
  if (logvisor::ErrorCount > ErrorRef) {
#if WIN_PAUSE
    system("PAUSE");
#endif
    return nullptr;
  }

  return newProj;
}

static std::unique_ptr<ToolBase> MakeSelectedTool(hecl::SystemString toolName, ToolPassInfo& info) {
  hecl::SystemString toolNameLower = toolName;
  hecl::ToLower(toolNameLower);

  if (toolNameLower == _SYS_STR("init")) {
    return std::make_unique<ToolInit>(info);
  }

  if (toolNameLower == _SYS_STR("spec")) {
    return std::make_unique<ToolSpec>(info);
  }

  if (toolNameLower == _SYS_STR("extract")) {
    return std::make_unique<ToolExtract>(info);
  }

  if (toolNameLower == _SYS_STR("cook")) {
    return std::make_unique<ToolCook>(info);
  }

  if (toolNameLower == _SYS_STR("package") || toolNameLower == _SYS_STR("pack")) {
    return std::make_unique<ToolPackage>(info);
  }

#if HECL_HAS_NOD
  if (toolNameLower == _SYS_STR("image")) {
    return std::make_unique<ToolImage>(info);
  }
#endif

  if (toolNameLower == _SYS_STR("help")) {
    return std::make_unique<ToolHelp>(info);
  }

  std::unique_ptr<FILE, decltype(&std::fclose)> fp{hecl::Fopen(toolName.c_str(), _SYS_STR("rb")), std::fclose};
  if (fp == nullptr) {
    LogModule.report(logvisor::Error, fmt(_SYS_STR("unrecognized tool '{}'")), toolNameLower);
    return nullptr;
  }
  fp.reset();

  /* Shortcut-case: implicit extract */
  info.args.insert(info.args.begin(), std::move(toolName));
  return std::make_unique<ToolExtract>(info);
}

#if _WIN32
int wmain(int argc, const wchar_t** argv)
#else
/* SIGWINCH should do nothing */
static void SIGWINCHHandler(int sig) {}
int main(int argc, const char** argv)
#endif
{
  if (argc > 1 && !hecl::StrCmp(argv[1], _SYS_STR("--dlpackage"))) {
    fmt::print(fmt("{}\n"), HECL_DLPACKAGE);
    return 100;
  }

#if _WIN32
  CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
#else
  std::setlocale(LC_ALL, "en-US.UTF-8");
#endif

  /* Xterm check */
#if _WIN32
  const char* conemuANSI = getenv("ConEmuANSI");
  if (conemuANSI && !strcmp(conemuANSI, "ON"))
    XTERM_COLOR = true;
#else
  const char* term = getenv("TERM");
  if (term && !strncmp(term, "xterm", 5))
    XTERM_COLOR = true;
  signal(SIGWINCH, SIGWINCHHandler);
#endif
  signal(SIGINT, SIGINTHandler);

  logvisor::RegisterStandardExceptions();
  logvisor::RegisterConsoleLogger();
  atSetExceptionHandler(AthenaExc);

  /* Basic usage check */
  if (argc == 1) {
    printHelp(argv[0]);
#if WIN_PAUSE
    system("PAUSE");
#endif
    return 0;
  } else if (argc == 0) {
    printHelp(_SYS_STR("hecl"));
#if WIN_PAUSE
    system("PAUSE");
#endif
    return 0;
  }

  /* Prepare DataSpecs */
  HECLRegisterDataSpecs();

  /* Assemble common tool pass info */
  ToolPassInfo info = CreateInfo(argc, argv);

  /* Attempt to find hecl project */
  auto project = FindProject(info.cwd);
  if (project != nullptr) {
    info.project = project.get();
  }

  /* Construct selected tool */
  const size_t MakeToolErrorRef = logvisor::ErrorCount;
  auto tool = MakeSelectedTool(argv[1], info);
  if (logvisor::ErrorCount > MakeToolErrorRef) {
#if WIN_PAUSE
    system("PAUSE");
#endif
    return 1;
  }
  if (info.verbosityLevel) {
    LogModule.report(logvisor::Info, fmt(_SYS_STR("Constructed tool '{}' {}\n")), tool->toolName(),
                     info.verbosityLevel);
  }

  /* Run tool */
  const size_t RunToolErrorRef = logvisor::ErrorCount;
  ToolPtr = tool.get();
  const int retval = tool->run();
  ToolPtr = nullptr;
  if (logvisor::ErrorCount > RunToolErrorRef) {
    hecl::blender::Connection::Shutdown();
#if WIN_PAUSE
    system("PAUSE");
#endif
    return 1;
  }

  hecl::blender::Connection::Shutdown();
#if WIN_PAUSE
  system("PAUSE");
#endif
  return retval;
}
<|endoftext|>


<commit_before>//===- unittests/Basic/SourceManagerTest.cpp ------ SourceManager tests ---===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Config/config.h"

#include "gtest/gtest.h"

using namespace llvm;
using namespace clang;

namespace {

// The test fixture.
class SourceManagerTest : public ::testing::Test {
protected:
  SourceManagerTest()
    : FileMgr(FileMgrOpts),
      DiagID(new DiagnosticIDs()),
      Diags(DiagID, new IgnoringDiagConsumer()),
      SourceMgr(Diags, FileMgr) {
    TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
    Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
  }

  FileSystemOptions FileMgrOpts;
  FileManager FileMgr;
  llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
  DiagnosticsEngine Diags;
  SourceManager SourceMgr;
  LangOptions LangOpts;
  TargetOptions TargetOpts;
  llvm::IntrusiveRefCntPtr<TargetInfo> Target;
};

class VoidModuleLoader : public ModuleLoader {
  virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
                             Module::NameVisibilityKind Visibility,
                             bool IsInclusionDirective) {
    return 0;
  }
};

TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
  const char *source =
    "#define M(x) [x]\n"
    "M(foo)";
  MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
  FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf);

  VoidModuleLoader ModLoader;
  HeaderSearch HeaderInfo(FileMgr, Diags);
  Preprocessor PP(Diags, LangOpts,
                  Target.getPtr(),
                  SourceMgr, HeaderInfo, ModLoader,
                  /*IILookup =*/ 0,
                  /*OwnsHeaderSearch =*/false,
                  /*DelayInitialization =*/ false);
  PP.EnterMainSourceFile();

  std::vector<Token> toks;
  while (1) {
    Token tok;
    PP.Lex(tok);
    if (tok.is(tok::eof))
      break;
    toks.push_back(tok);
  }

  // Make sure we got the tokens that we expected.
  ASSERT_EQ(3U, toks.size());
  ASSERT_EQ(tok::l_square, toks[0].getKind());
  ASSERT_EQ(tok::identifier, toks[1].getKind());
  ASSERT_EQ(tok::r_square, toks[2].getKind());

  SourceLocation lsqrLoc = toks[0].getLocation();
  SourceLocation idLoc = toks[1].getLocation();
  SourceLocation rsqrLoc = toks[2].getLocation();

  SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1);
  SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6);
  ASSERT_TRUE(macroExpStartLoc.isFileID());
  ASSERT_TRUE(macroExpEndLoc.isFileID());

  llvm::SmallString<32> str;
  ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str));
  ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str));

  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc));
  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc));
  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc));
  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc));
}

#if defined(LLVM_ON_UNIX)

TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
  const char *header =
    "#define FM(x,y) x\n";

  const char *main =
    "#include \"/test-header.h\"\n"
    "#define VAL 0\n"
    "FM(VAL,0)\n"
    "FM(0,VAL)\n"
    "FM(FM(0,VAL),0)\n"
    "#define CONCAT(X, Y) X##Y\n"
    "CONCAT(1,1)\n";

  MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header);
  MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main);
  FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(mainBuf);

  const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
                                                 headerBuf->getBufferSize(), 0);
  SourceMgr.overrideFileContents(headerFile, headerBuf);

  VoidModuleLoader ModLoader;
  HeaderSearch HeaderInfo(FileMgr, Diags);
  Preprocessor PP(Diags, LangOpts,
                  Target.getPtr(),
                  SourceMgr, HeaderInfo, ModLoader,
                  /*IILookup =*/ 0,
                  /*OwnsHeaderSearch =*/false,
                  /*DelayInitialization =*/ false);
  PP.EnterMainSourceFile();

  std::vector<Token> toks;
  while (1) {
    Token tok;
    PP.Lex(tok);
    if (tok.is(tok::eof))
      break;
    toks.push_back(tok);
  }

  // Make sure we got the tokens that we expected.
  ASSERT_EQ(4U, toks.size());
  ASSERT_EQ(tok::numeric_constant, toks[0].getKind());
  ASSERT_EQ(tok::numeric_constant, toks[1].getKind());
  ASSERT_EQ(tok::numeric_constant, toks[2].getKind());
  ASSERT_EQ(tok::numeric_constant, toks[3].getKind());

  SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13);
  SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8);
  SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4);
  SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7);
  SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22);
  defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc);
  loc1 = SourceMgr.getMacroArgExpandedLocation(loc1);
  loc2 = SourceMgr.getMacroArgExpandedLocation(loc2);
  loc3 = SourceMgr.getMacroArgExpandedLocation(loc3);
  defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2);

  EXPECT_TRUE(defLoc.isFileID());
  EXPECT_TRUE(loc1.isFileID());
  EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2));
  EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3));
  EXPECT_EQ(loc2, toks[1].getLocation());
  EXPECT_EQ(loc3, toks[2].getLocation());
  EXPECT_TRUE(defLoc2.isFileID());
}

#endif

} // anonymous namespace
<commit_msg>clang/unittests/Basic/SourceManagerTest.cpp: Fixup corresponding to r147387.<commit_after>//===- unittests/Basic/SourceManagerTest.cpp ------ SourceManager tests ---===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Config/config.h"

#include "gtest/gtest.h"

using namespace llvm;
using namespace clang;

namespace {

// The test fixture.
class SourceManagerTest : public ::testing::Test {
protected:
  SourceManagerTest()
    : FileMgr(FileMgrOpts),
      DiagID(new DiagnosticIDs()),
      Diags(DiagID, new IgnoringDiagConsumer()),
      SourceMgr(Diags, FileMgr) {
    TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
    Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
  }

  FileSystemOptions FileMgrOpts;
  FileManager FileMgr;
  llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
  DiagnosticsEngine Diags;
  SourceManager SourceMgr;
  LangOptions LangOpts;
  TargetOptions TargetOpts;
  llvm::IntrusiveRefCntPtr<TargetInfo> Target;
};

class VoidModuleLoader : public ModuleLoader {
  virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
                             Module::NameVisibilityKind Visibility,
                             bool IsInclusionDirective) {
    return 0;
  }
};

TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
  const char *source =
    "#define M(x) [x]\n"
    "M(foo)";
  MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
  FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf);

  VoidModuleLoader ModLoader;
  HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts);
  Preprocessor PP(Diags, LangOpts,
                  Target.getPtr(),
                  SourceMgr, HeaderInfo, ModLoader,
                  /*IILookup =*/ 0,
                  /*OwnsHeaderSearch =*/false,
                  /*DelayInitialization =*/ false);
  PP.EnterMainSourceFile();

  std::vector<Token> toks;
  while (1) {
    Token tok;
    PP.Lex(tok);
    if (tok.is(tok::eof))
      break;
    toks.push_back(tok);
  }

  // Make sure we got the tokens that we expected.
  ASSERT_EQ(3U, toks.size());
  ASSERT_EQ(tok::l_square, toks[0].getKind());
  ASSERT_EQ(tok::identifier, toks[1].getKind());
  ASSERT_EQ(tok::r_square, toks[2].getKind());

  SourceLocation lsqrLoc = toks[0].getLocation();
  SourceLocation idLoc = toks[1].getLocation();
  SourceLocation rsqrLoc = toks[2].getLocation();

  SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1);
  SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6);
  ASSERT_TRUE(macroExpStartLoc.isFileID());
  ASSERT_TRUE(macroExpEndLoc.isFileID());

  llvm::SmallString<32> str;
  ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str));
  ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str));

  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc));
  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc));
  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc));
  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc));
}

#if defined(LLVM_ON_UNIX)

TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
  const char *header =
    "#define FM(x,y) x\n";

  const char *main =
    "#include \"/test-header.h\"\n"
    "#define VAL 0\n"
    "FM(VAL,0)\n"
    "FM(0,VAL)\n"
    "FM(FM(0,VAL),0)\n"
    "#define CONCAT(X, Y) X##Y\n"
    "CONCAT(1,1)\n";

  MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header);
  MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main);
  FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(mainBuf);

  const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
                                                 headerBuf->getBufferSize(), 0);
  SourceMgr.overrideFileContents(headerFile, headerBuf);

  VoidModuleLoader ModLoader;
  HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts);
  Preprocessor PP(Diags, LangOpts,
                  Target.getPtr(),
                  SourceMgr, HeaderInfo, ModLoader,
                  /*IILookup =*/ 0,
                  /*OwnsHeaderSearch =*/false,
                  /*DelayInitialization =*/ false);
  PP.EnterMainSourceFile();

  std::vector<Token> toks;
  while (1) {
    Token tok;
    PP.Lex(tok);
    if (tok.is(tok::eof))
      break;
    toks.push_back(tok);
  }

  // Make sure we got the tokens that we expected.
  ASSERT_EQ(4U, toks.size());
  ASSERT_EQ(tok::numeric_constant, toks[0].getKind());
  ASSERT_EQ(tok::numeric_constant, toks[1].getKind());
  ASSERT_EQ(tok::numeric_constant, toks[2].getKind());
  ASSERT_EQ(tok::numeric_constant, toks[3].getKind());

  SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13);
  SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8);
  SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4);
  SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7);
  SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22);
  defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc);
  loc1 = SourceMgr.getMacroArgExpandedLocation(loc1);
  loc2 = SourceMgr.getMacroArgExpandedLocation(loc2);
  loc3 = SourceMgr.getMacroArgExpandedLocation(loc3);
  defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2);

  EXPECT_TRUE(defLoc.isFileID());
  EXPECT_TRUE(loc1.isFileID());
  EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2));
  EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3));
  EXPECT_EQ(loc2, toks[1].getLocation());
  EXPECT_EQ(loc3, toks[2].getLocation());
  EXPECT_TRUE(defLoc2.isFileID());
}

#endif

} // anonymous namespace
<|endoftext|>