<commit_before>/*
   Copyright 2016 Mitchell Young

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#pragma once

#include <H5Cpp.h>
#include <cassert>
#include <memory>
#include <sstream>
#include <string>

#include "blitz_typedefs.hpp"
#include "error.hpp"
#include "global_config.hpp"

namespace mocc {
/**
 * Enumeration of the supported HDF5 access patterns supported by \ref
 * H5Node.
 */
enum class H5Access {
    /**
     * Leave file as-is with read-only permissions.
     */
    READ,
    /**
     * Delete any existing file, opening a new one with write permissions.
     */
    WRITE,
    /**
     * Open a file as-is, with read-write permissions.
     */
    APPEND,
};

/**
 * Wrapper class for the HDF5 library. An instance of this class is similar
 * to the HDF5 CommonFG class, with extra stuff to make it easier to work
 * with.
 */
class H5Node {
public:
    H5Node(std::string filename, H5Access access);

    /**
     * \brief Create a new group in the HDF5 file.
     *
     * \param path the path to the group to be created
     * \return a new \ref H5Node pointing to the new group
     *
     * This method produces a new HDF5 group in the file, located at the
     * path specified relative to the \ref H5Node upon which this method is
     * called. If the path contains a leading slash ('/'), the path will be
     * relative to the root of the file.
     */
    H5Node create_group(std::string path);

    /**
     * \brief Create a link to an existing group somewhere else in the HDF5 file
     *
     * \param source the path to the source dataset or group, which must already
     * exist in the file. An empty string or "." will refer to the node itself.
     * \param destination the path for the link
     * \param type the type of HDF5 link to create. Default: HARD
     *
     * This will create a new link to an existing object in the HDF5 file. A
     * link is pretty much a shortcut to existing data.
     */
    void create_link(std::string source, std::string destination,
                     H5Link type = H5Link::HARD);

    /**
     * \brief Return a pointer to the underlying H5::CommonFG
     *
     * This is provided so that client code can use the full-blown HDF5
     * library to interact with the file.
     */
    H5::CommonFG *get()
    {
        return node_.get();
    }

    /**
     * \brief Return an \ref H5Node pointing to the path specified.
     */
    H5Node operator[](std::string path)
    {
        std::shared_ptr<H5::CommonFG> g(new H5::Group(node_->openGroup(path)));
        return H5Node(g, access_);
    }

    /**
     * \brief Return the dimensions of the dataset specified by the path
     */
    std::vector<hsize_t> dimensions(std::string path);

    /**
     * \brief Write an std::vector<double> to the file, assuming
     * one dimension.
     */
    void write(std::string path, const VecF &data);

    /**
     * \brief Write an std::vector<double> to the file, using specified
     * dimensions.
     */
    void write(std::string path, const VecF &data, VecI dims);

    void write(std::string path, const std::string &str);

    /**
     * \brief Write a 1-D Blitz array to an HDF5 file, possibly reshaping
     */
    void write(std::string path, const ArrayB1 &data, VecI dims);

    /**
     * \brief Write a Blitz++ array to the HDF5 node.
     *
     * This can be used to write a Blitz array of any dimension to an HDF5
     * file. This passes the pointer to the beginning of the data and
     * allows the HDF5 library to just copy directly, so it is required that
     * the data be stored contiguously, and will throw an exception if this
     * isnt the case. We also assume that the data type stored in the Blitz
     * array is double precision.
     */
    template <class BlitzArray>
    void write(std::string path, const BlitzArray &data)
    {
        // First, make sure that the data is contiguous in memory. We are
        // going to do a direct copy, using the data() pointer to the
        // beginning of the array, so this is crucial.
        if (!data.isStorageContiguous()) {
            throw EXCEPT("Blitz data is not contiguous.");
        }

        int ndim = data.dimensions();
        std::vector<hsize_t> dims;
        size_t size = 1;
        for (int i = 0; i < ndim; i++) {
            dims.push_back(data.extent(i));
            size *= data.extent(i);
        }

        if (data.size() != size) {
            throw EXCEPT("Something fishy is going on with array "
                         "dimensions.");
        }

        try {
            H5::DataSpace space(dims.size(), dims.data());
            H5::DataSet dataset =
                node_->createDataSet(path, H5::PredType::NATIVE_DOUBLE, space);
            dataset.write(data.data(), H5::PredType::NATIVE_DOUBLE);
        } catch (...) {
            std::stringstream msg;
            msg << "Failed to write dataset: " << path;
            throw EXCEPT(msg.str().c_str());
        }

        return;
    }

    /**
     * \brief Version of \ref H5Node::write() for writing scalar integers.
     */
    void write(std::string path, int data)
    {
        hsize_t dims_a[1];

        dims_a[0] = 1;

        try {
            H5::DataSpace space(1, dims_a);
            H5::DataSet dataset =
                node_->createDataSet(path, H5::PredType::NATIVE_INT, space);
            dataset.write(&data, H5::PredType::NATIVE_INT);
        } catch (...) {
            std::stringstream msg;
            msg << "Failed to write dataset: " << path;
            throw EXCEPT(msg.str().c_str());
        }
        return;
    }

    /**
     * \brief Write a scalar unsigned long integer.
     */
    void write(std::string path, unsigned long data)
    {
        hsize_t dims_a[1];

        dims_a[0] = 1;

        try {
            H5::DataSpace space(1, dims_a);
            H5::DataSet dataset =
                node_->createDataSet(path, H5::PredType::NATIVE_ULONG, space);
            dataset.write(&data, H5::PredType::NATIVE_ULONG);
        } catch (...) {
            std::stringstream msg;
            msg << "Failed to write dataset: " << path;
            throw EXCEPT(msg.str().c_str());
        }
        return;
    }

    /**
     * \brief Read data from an \ref H5Node into an STL vector
     */
    void read(std::string path, std::vector<double> &data) const;

    /**
     * \brief Read data from an \ref H5Node into a 1-D Blitz array
     *
     * Dimensionality of the data in the HDF5 file is allowed to be more
     * than 1-D, in which case the data is copied linearly into the 1-D
     * Blitz array. This is not an overload of the regular \c read() method
     * to avoid the potential for error.
     */
    void read_1d(std::string path, ArrayB1 &data) const;

    /**
     * \brief Read data from an \ref H5Node into a Blitz++ array.
     *
     *
     * This will attempt to read the dataset specified by the path relative
     * the location of the \ref H5Node into the passed Blitz array.
     * \pre One of the following must be true:
     *  - The array is one-dimensional, or
     *  - The array has the same dimensions as the HDF5 database.
     * \pre One of the following musht be true:
     *  - The array is empty (size == 0)
     *  - The array has space allocated for the same number of elements as
     *  the HDF5 dataset, and \c isStorageContiguous() must return \c true.
     */
    template <class BlitzArray>
    void read(std::string path, BlitzArray &data) const
    {
        if ((data.size() > 0) && !data.isStorageContiguous()) {
            throw EXCEPT("Blitz data is not contiguous");
        }

        H5::DataSet dataset;
        H5::DataSpace dataspace;
        int ndim   = -1;
        int h5size = -1;
        std::vector<hsize_t> dims;
        try {
            dataset   = node_->openDataSet(path);
            dataspace = dataset.getSpace();
            ndim      = dataspace.getSimpleExtentNdims();
            h5size    = dataspace.getSimpleExtentNpoints();
            dims.resize(ndim);
            dataspace.getSimpleExtentDims(dims.data());
        } catch (...) {
            std::stringstream msg;
            msg << "Failed to access dataset: " << path;
            throw EXCEPT(msg.str().c_str());
        }

        if ((int)ndim != data.dimensions()) {
        }

        auto shape = data.shape();
        auto size  = data.size();

        if (size == 0) {
            // Allocate space in the destination array
            if (data.dimensions() == 1) {
                data.resize(h5size);
            } else {
                if (data.dimensions() != ndim) {
                    throw EXCEPT("Array and dataset dimensionality "
                                 "disagree.");
                }
                for (int i = 0; i < ndim; i++) {
                    shape[i] = dims[i];
                }
                data.resize(shape);
            }
        } else {
            if (data.dimensions() == 1) {
                if ((int)data.size() != h5size) {
                    std::cerr << data.size() << " " << h5size << std::endl;
                    throw EXCEPT("Incorrect array size.");
                }
            } else {
                // Make sure the dimensions match
                for (int i = 0; i < ndim; i++) {
                    if (shape[i] != (int)dims[i]) {
                        throw EXCEPT("Incorrect array shape.");
                    }
                }
            }
        }

        try {
            dataset.read(data.data(), H5::PredType::NATIVE_DOUBLE);
        } catch (...) {
            std::stringstream msg;
            msg << "Failed to read dataset: " << path;
            throw EXCEPT(msg.str());
        }

        return;
    }

    /**
     * Write data to an HDF5 location using iterators.
     *
     * \param path the path to the dataset, relative to \c node. If
     * preceeded by a '/', the path is absolute and will resolve to a
     * location relative to the root of the HDF5 file.
     * \param first an iterator pointing to the beginning of the data to be
     * written.
     * \param last an iterator past the end of the data to be written.
     * \param dims a vector of ints containing the dimensions of the data
     */
    template <class InputIterator>
    InputIterator write(std::string path, InputIterator first,
                        InputIterator last, VecI dims)
    {
        std::vector<hsize_t> dims_a;
        int n = 1;
        for (auto di : dims) {
            n *= di;
            dims_a.push_back(di);
        }

        VecF d(n);
        std::copy(first, last, d.begin());
        assert((int)d.size() == n);

        try {
            H5::DataSpace space(dims.size(), dims_a.data());
            H5::DataSet dataset =
                node_->createDataSet(path, H5::PredType::NATIVE_DOUBLE, space);
            dataset.write(d.data(), H5::PredType::NATIVE_DOUBLE);
        } catch (...) {
            std::stringstream msg;
            msg << "Failed to write dataset: " << path;
            throw EXCEPT(msg.str().c_str());
        }
        return last;
    }

private:
    H5Node(std::shared_ptr<H5::CommonFG> node_, H5Access access);

    // Pointer to the file object. Null if not the root node of the file.
    std::shared_ptr<H5::H5File> file_;
    std::shared_ptr<H5::CommonFG> node_;
    H5Access access_;
};
}
<commit_msg>Add HDF5 link spec enumeration<commit_after>/*
   Copyright 2016 Mitchell Young

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#pragma once

#include <H5Cpp.h>
#include <cassert>
#include <memory>
#include <sstream>
#include <string>

#include "blitz_typedefs.hpp"
#include "error.hpp"
#include "global_config.hpp"

namespace mocc {
/**
 * Enumeration of the supported HDF5 access patterns supported by \ref
 * H5Node.
 */
enum class H5Access {
    /**
     * Leave file as-is with read-only permissions.
     */
    READ,
    /**
     * Delete any existing file, opening a new one with write permissions.
     */
    WRITE,
    /**
     * Open a file as-is, with read-write permissions.
     */
    APPEND,
};

enum class H5Link { HARD, SOFT };

/**
 * \brief Wrapper class to selected HDF5 functionality.
 *
 * Wrapper class for the HDF5 library. An instance of this class is similar
 * to the HDF5 CommonFG class, with extra stuff to make it easier to work
 * with.
 */
class H5Node {
public:
    H5Node(std::string filename, H5Access access);

    /**
     * \brief Create a new group in the HDF5 file.
     *
     * \param path the path to the group to be created
     * \return a new \ref H5Node pointing to the new group
     *
     * This method produces a new HDF5 group in the file, located at the
     * path specified relative to the \ref H5Node upon which this method is
     * called. If the path contains a leading slash ('/'), the path will be
     * relative to the root of the file.
     */
    H5Node create_group(std::string path);

    /**
     * \brief Create a link to an existing group somewhere else in the HDF5 file
     *
     * \param source the path to the source dataset or group, which must already
     * exist in the file. An empty string or "." will refer to the node itself.
     * \param destination the path for the link
     * \param type the type of HDF5 link to create. Default: HARD
     *
     * This will create a new link to an existing object in the HDF5 file. A
     * link is pretty much a shortcut to existing data.
     */
    void create_link(std::string source, std::string destination,
                     H5Link type = H5Link::HARD);

    /**
     * \brief Return a pointer to the underlying H5::CommonFG
     *
     * This is provided so that client code can use the full-blown HDF5
     * library to interact with the file.
     */
    H5::CommonFG *get()
    {
        return node_.get();
    }

    /**
     * \brief Return an \ref H5Node pointing to the path specified.
     */
    H5Node operator[](std::string path)
    {
        std::shared_ptr<H5::CommonFG> g(new H5::Group(node_->openGroup(path)));
        return H5Node(g, access_);
    }

    /**
     * \brief Return the dimensions of the dataset specified by the path
     */
    std::vector<hsize_t> dimensions(std::string path);

    /**
     * \brief Write an std::vector<double> to the file, assuming
     * one dimension.
     */
    void write(std::string path, const VecF &data);

    /**
     * \brief Write an std::vector<double> to the file, using specified
     * dimensions.
     */
    void write(std::string path, const VecF &data, VecI dims);

    void write(std::string path, const std::string &str);

    /**
     * \brief Write a 1-D Blitz array to an HDF5 file, possibly reshaping
     */
    void write(std::string path, const ArrayB1 &data, VecI dims);

    /**
     * \brief Write a Blitz++ array to the HDF5 node.
     *
     * This can be used to write a Blitz array of any dimension to an HDF5
     * file. This passes the pointer to the beginning of the data and
     * allows the HDF5 library to just copy directly, so it is required that
     * the data be stored contiguously, and will throw an exception if this
     * isnt the case. We also assume that the data type stored in the Blitz
     * array is double precision.
     */
    template <class BlitzArray>
    void write(std::string path, const BlitzArray &data)
    {
        // First, make sure that the data is contiguous in memory. We are
        // going to do a direct copy, using the data() pointer to the
        // beginning of the array, so this is crucial.
        if (!data.isStorageContiguous()) {
            throw EXCEPT("Blitz data is not contiguous.");
        }

        int ndim = data.dimensions();
        std::vector<hsize_t> dims;
        size_t size = 1;
        for (int i = 0; i < ndim; i++) {
            dims.push_back(data.extent(i));
            size *= data.extent(i);
        }

        if (data.size() != size) {
            throw EXCEPT("Something fishy is going on with array "
                         "dimensions.");
        }

        try {
            H5::DataSpace space(dims.size(), dims.data());
            H5::DataSet dataset =
                node_->createDataSet(path, H5::PredType::NATIVE_DOUBLE, space);
            dataset.write(data.data(), H5::PredType::NATIVE_DOUBLE);
        } catch (...) {
            std::stringstream msg;
            msg << "Failed to write dataset: " << path;
            throw EXCEPT(msg.str().c_str());
        }

        return;
    }

    /**
     * \brief Version of \ref H5Node::write() for writing scalar integers.
     */
    void write(std::string path, int data)
    {
        hsize_t dims_a[1];

        dims_a[0] = 1;

        try {
            H5::DataSpace space(1, dims_a);
            H5::DataSet dataset =
                node_->createDataSet(path, H5::PredType::NATIVE_INT, space);
            dataset.write(&data, H5::PredType::NATIVE_INT);
        } catch (...) {
            std::stringstream msg;
            msg << "Failed to write dataset: " << path;
            throw EXCEPT(msg.str().c_str());
        }
        return;
    }

    /**
     * \brief Write a scalar unsigned long integer.
     */
    void write(std::string path, unsigned long data)
    {
        hsize_t dims_a[1];

        dims_a[0] = 1;

        try {
            H5::DataSpace space(1, dims_a);
            H5::DataSet dataset =
                node_->createDataSet(path, H5::PredType::NATIVE_ULONG, space);
            dataset.write(&data, H5::PredType::NATIVE_ULONG);
        } catch (...) {
            std::stringstream msg;
            msg << "Failed to write dataset: " << path;
            throw EXCEPT(msg.str().c_str());
        }
        return;
    }

    /**
     * \brief Read data from an \ref H5Node into an STL vector
     */
    void read(std::string path, std::vector<double> &data) const;

    /**
     * \brief Read data from an \ref H5Node into a 1-D Blitz array
     *
     * Dimensionality of the data in the HDF5 file is allowed to be more
     * than 1-D, in which case the data is copied linearly into the 1-D
     * Blitz array. This is not an overload of the regular \c read() method
     * to avoid the potential for error.
     */
    void read_1d(std::string path, ArrayB1 &data) const;

    /**
     * \brief Read data from an \ref H5Node into a Blitz++ array.
     *
     *
     * This will attempt to read the dataset specified by the path relative
     * the location of the \ref H5Node into the passed Blitz array.
     * \pre One of the following must be true:
     *  - The array is one-dimensional, or
     *  - The array has the same dimensions as the HDF5 database.
     * \pre One of the following musht be true:
     *  - The array is empty (size == 0)
     *  - The array has space allocated for the same number of elements as
     *  the HDF5 dataset, and \c isStorageContiguous() must return \c true.
     */
    template <class BlitzArray>
    void read(std::string path, BlitzArray &data) const
    {
        if ((data.size() > 0) && !data.isStorageContiguous()) {
            throw EXCEPT("Blitz data is not contiguous");
        }

        H5::DataSet dataset;
        H5::DataSpace dataspace;
        int ndim   = -1;
        int h5size = -1;
        std::vector<hsize_t> dims;
        try {
            dataset   = node_->openDataSet(path);
            dataspace = dataset.getSpace();
            ndim      = dataspace.getSimpleExtentNdims();
            h5size    = dataspace.getSimpleExtentNpoints();
            dims.resize(ndim);
            dataspace.getSimpleExtentDims(dims.data());
        } catch (...) {
            std::stringstream msg;
            msg << "Failed to access dataset: " << path;
            throw EXCEPT(msg.str().c_str());
        }

        if ((int)ndim != data.dimensions()) {
        }

        auto shape = data.shape();
        auto size  = data.size();

        if (size == 0) {
            // Allocate space in the destination array
            if (data.dimensions() == 1) {
                data.resize(h5size);
            } else {
                if (data.dimensions() != ndim) {
                    throw EXCEPT("Array and dataset dimensionality "
                                 "disagree.");
                }
                for (int i = 0; i < ndim; i++) {
                    shape[i] = dims[i];
                }
                data.resize(shape);
            }
        } else {
            if (data.dimensions() == 1) {
                if ((int)data.size() != h5size) {
                    std::cerr << data.size() << " " << h5size << std::endl;
                    throw EXCEPT("Incorrect array size.");
                }
            } else {
                // Make sure the dimensions match
                for (int i = 0; i < ndim; i++) {
                    if (shape[i] != (int)dims[i]) {
                        throw EXCEPT("Incorrect array shape.");
                    }
                }
            }
        }

        try {
            dataset.read(data.data(), H5::PredType::NATIVE_DOUBLE);
        } catch (...) {
            std::stringstream msg;
            msg << "Failed to read dataset: " << path;
            throw EXCEPT(msg.str());
        }

        return;
    }

    /**
     * Write data to an HDF5 location using iterators.
     *
     * \param path the path to the dataset, relative to \c node. If
     * preceeded by a '/', the path is absolute and will resolve to a
     * location relative to the root of the HDF5 file.
     * \param first an iterator pointing to the beginning of the data to be
     * written.
     * \param last an iterator past the end of the data to be written.
     * \param dims a vector of ints containing the dimensions of the data
     */
    template <class InputIterator>
    InputIterator write(std::string path, InputIterator first,
                        InputIterator last, VecI dims)
    {
        std::vector<hsize_t> dims_a;
        int n = 1;
        for (auto di : dims) {
            n *= di;
            dims_a.push_back(di);
        }

        VecF d(n);
        std::copy(first, last, d.begin());
        assert((int)d.size() == n);

        try {
            H5::DataSpace space(dims.size(), dims_a.data());
            H5::DataSet dataset =
                node_->createDataSet(path, H5::PredType::NATIVE_DOUBLE, space);
            dataset.write(d.data(), H5::PredType::NATIVE_DOUBLE);
        } catch (...) {
            std::stringstream msg;
            msg << "Failed to write dataset: " << path;
            throw EXCEPT(msg.str().c_str());
        }
        return last;
    }

private:
    H5Node(std::shared_ptr<H5::CommonFG> node_, H5Access access);

    // Pointer to the file object. Null if not the root node of the file.
    std::shared_ptr<H5::H5File> file_;
    std::shared_ptr<H5::CommonFG> node_;
    H5Access access_;
};
}
<|endoftext|>


<commit_before>#include	"FTVectoriser.h"
#include	"FTGL.h"

FTContour::FTContour()
:	kMAXPOINTS( 1000)
{
	pointList.reserve( kMAXPOINTS);
}

FTContour::~FTContour()
{
	pointList.clear();
}

void FTContour::AddPoint( const float x, const float y)
{
	ftPoint point( static_cast<float>( x), static_cast<float>( y), 0.0);

	// Eliminate duplicate points.
	if( ( pointList[pointList.size() - 1] != point) && pointList[0] != point)
	{
		pointList.push_back( point);
	}
}

FTVectoriser::FTVectoriser( const FT_Glyph glyph)
:	contourFlag(0),
	contour(0),
	kBSTEPSIZE( 0.2)

{
	FT_OutlineGlyph outline = (FT_OutlineGlyph)glyph;
	ftOutline = outline->outline;

	contourList.reserve( ftOutline.n_contours);
}

FTVectoriser::~FTVectoriser()
{
	for( int c = 0; c < contours(); ++c)
	{
		delete contourList[c];
	}

	contourList.clear();
}

int FTVectoriser::points()
{
	int s = 0;
	for( int c = 0; c < contours(); ++c)
	{
		s += contourList[c]->size();
	}

	return s;
}

bool FTVectoriser::Ingest()
{
    if ( ( ftOutline.n_contours < 1) || ( ftOutline.n_points < 3))
		return false;

	short first = 0;
	short last;
	const short cont = ftOutline.n_contours;

	for( short c = 0; c < cont; ++c)
	{
		contour = new FTContour;
		contourFlag = ftOutline.flags;
		last = ftOutline.contours[c];

		for( short p = first; p <= last; ++p)
		{
			switch( ftOutline.tags[p])
			{
				case FT_Curve_Tag_Conic:
					p += Conic( p, first, last);
					break;
				case FT_Curve_Tag_Cubic:
					p += Cubic( p, first, last);
					break;
				case FT_Curve_Tag_On:
				default:
 					contour->AddPoint( ftOutline.points[p].x, ftOutline.points[p].y);
			}
		}

		contourList.push_back( contour);
		first = last + 1;
	}

	return true;
}

int FTVectoriser::Conic( const int index, const int first, const int last)
{
	int next = index + 1;
	int prev = index - 1;

	if( index == last)
		next = first;

	if( index == first)
		prev = last;

	if( ftOutline.tags[next] != FT_Curve_Tag_Conic)
	{
		ctrlPtArray[0][0] = ftOutline.points[prev].x;	ctrlPtArray[0][1] = ftOutline.points[prev].y;
		ctrlPtArray[1][0] = ftOutline.points[index].x;	ctrlPtArray[1][1] = ftOutline.points[index].y;
		ctrlPtArray[2][0] = ftOutline.points[next].x;	ctrlPtArray[2][1] = ftOutline.points[next].y;

		evaluateCurve( 2);
		return 1;
	}
	else
	{
		int next2 = next + 1;
		if( next == last)
			next2 = first;

		//create a phantom point
		float x = ( ftOutline.points[index].x + ftOutline.points[next].x) / 2;
		float y = ( ftOutline.points[index].y + ftOutline.points[next].y) / 2;

		// process first curve
		ctrlPtArray[0][0] = ftOutline.points[prev].x;	ctrlPtArray[0][1] = ftOutline.points[prev].y;
		ctrlPtArray[1][0] = ftOutline.points[index].x;	ctrlPtArray[1][1] = ftOutline.points[index].y;
		ctrlPtArray[2][0] = x;							ctrlPtArray[2][1] = y;

		evaluateCurve( 2);

		// process second curve
		ctrlPtArray[0][0] = x;							ctrlPtArray[0][1] = y;
		ctrlPtArray[1][0] = ftOutline.points[next].x;	ctrlPtArray[1][1] = ftOutline.points[next].y;
		ctrlPtArray[2][0] = ftOutline.points[next2].x;	ctrlPtArray[2][1] = ftOutline.points[next2].y;
		evaluateCurve( 2);

		return 2;
	}
}

int FTVectoriser::Cubic( const int index, const int first, const int last)
{
	int next = index + 1;
	int prev = index - 1;

	if( index == last)
		next = first;

	int next2 = next + 1;

	if( next == last)
		next2 = first;

	if( index == first)
		prev = last;

	ctrlPtArray[0][0] = ftOutline.points[prev].x;		ctrlPtArray[0][1] = ftOutline.points[prev].y;
	ctrlPtArray[1][0] = ftOutline.points[index].x;		ctrlPtArray[1][1] = ftOutline.points[index].y;
	ctrlPtArray[2][0] = ftOutline.points[next].x;		ctrlPtArray[2][1] = ftOutline.points[next].y;
	ctrlPtArray[3][0] = ftOutline.points[next2].x;		ctrlPtArray[3][1] = ftOutline.points[next2].y;

	evaluateCurve( 3);
	return 2;
}

// De Casteljau algorithm supplied by Jed Soane
void FTVectoriser::deCasteljau( const float t, const int n)
{
    //Calculating successive b(i)'s using de Casteljau algorithm.
    for( int i = 1; i <= n; i++)
        for( int k = 0; k <= (n - i); k++)
        {
			bValues[i][k][0] = (1 - t) * bValues[i - 1][k][0] + t * bValues[i - 1][k + 1][0];
			bValues[i][k][1] = (1 - t) * bValues[i - 1][k][1] + t * bValues[i - 1][k + 1][1];
		}

    //Specify next vertex to be included on curve
	contour->AddPoint( bValues[n][0][0], bValues[n][0][1]);
}

// De Casteljau algorithm supplied by Jed Soane
void FTVectoriser::evaluateCurve( const int n)
{
    // setting the b(0) equal to the control points
    for( int i = 0; i <= n; i++)
	{
		bValues[0][i][0] = ctrlPtArray[i][0];
		bValues[0][i][1] = ctrlPtArray[i][1];
    } //end for(i..)

    float t;            					//parameter for curve point calc. [0.0, 1.0]

    for( int m = 0; m <= (1 / kBSTEPSIZE); m++)
    {
    	t = m * kBSTEPSIZE;
        deCasteljau( t, n);  //calls to evaluate point on curve att.
    } //end for(m...)
}

void FTVectoriser::Output( double* data)
{
	int i = 0;

	for( int c= 0; c < contours(); ++c)
	{
		const FTContour* contour = contourList[c];

		for( int p = 0; p < contour->size(); ++p)
		{
			data[i] = static_cast<double>(contour->pointList[p].x / 64.0f); // is 64 correct?
			data[i + 1] = static_cast<double>(contour->pointList[p].y / 64.0f);
			data[i + 2] = 0.0; // static_cast<double>(contour->pointList[p].z / 64.0f);
			i += 3;
		}
	}
}
<commit_msg>Removed redundant static_cast<float>()<commit_after>#include	"FTVectoriser.h"
#include	"FTGL.h"

FTContour::FTContour()
:	kMAXPOINTS( 1000)
{
	pointList.reserve( kMAXPOINTS);
}

FTContour::~FTContour()
{
	pointList.clear();
}

void FTContour::AddPoint( const float x, const float y)
{
	ftPoint point( x, y, 0.0);

	// Eliminate duplicate points.
	if( ( pointList[pointList.size() - 1] != point) && pointList[0] != point)
	{
		pointList.push_back( point);
	}
}

FTVectoriser::FTVectoriser( const FT_Glyph glyph)
:	contourFlag(0),
	contour(0),
	kBSTEPSIZE( 0.2)

{
	FT_OutlineGlyph outline = (FT_OutlineGlyph)glyph;
	ftOutline = outline->outline;

	contourList.reserve( ftOutline.n_contours);
}

FTVectoriser::~FTVectoriser()
{
	for( int c = 0; c < contours(); ++c)
	{
		delete contourList[c];
	}

	contourList.clear();
}

int FTVectoriser::points()
{
	int s = 0;
	for( int c = 0; c < contours(); ++c)
	{
		s += contourList[c]->size();
	}

	return s;
}

bool FTVectoriser::Ingest()
{
    if ( ( ftOutline.n_contours < 1) || ( ftOutline.n_points < 3))
		return false;

	short first = 0;
	short last;
	const short cont = ftOutline.n_contours;

	for( short c = 0; c < cont; ++c)
	{
		contour = new FTContour;
		contourFlag = ftOutline.flags;
		last = ftOutline.contours[c];

		for( short p = first; p <= last; ++p)
		{
			switch( ftOutline.tags[p])
			{
				case FT_Curve_Tag_Conic:
					p += Conic( p, first, last);
					break;
				case FT_Curve_Tag_Cubic:
					p += Cubic( p, first, last);
					break;
				case FT_Curve_Tag_On:
				default:
 					contour->AddPoint( ftOutline.points[p].x, ftOutline.points[p].y);
			}
		}

		contourList.push_back( contour);
		first = last + 1;
	}

	return true;
}

int FTVectoriser::Conic( const int index, const int first, const int last)
{
	int next = index + 1;
	int prev = index - 1;

	if( index == last)
		next = first;

	if( index == first)
		prev = last;

	if( ftOutline.tags[next] != FT_Curve_Tag_Conic)
	{
		ctrlPtArray[0][0] = ftOutline.points[prev].x;	ctrlPtArray[0][1] = ftOutline.points[prev].y;
		ctrlPtArray[1][0] = ftOutline.points[index].x;	ctrlPtArray[1][1] = ftOutline.points[index].y;
		ctrlPtArray[2][0] = ftOutline.points[next].x;	ctrlPtArray[2][1] = ftOutline.points[next].y;

		evaluateCurve( 2);
		return 1;
	}
	else
	{
		int next2 = next + 1;
		if( next == last)
			next2 = first;

		//create a phantom point
		float x = ( ftOutline.points[index].x + ftOutline.points[next].x) / 2;
		float y = ( ftOutline.points[index].y + ftOutline.points[next].y) / 2;

		// process first curve
		ctrlPtArray[0][0] = ftOutline.points[prev].x;	ctrlPtArray[0][1] = ftOutline.points[prev].y;
		ctrlPtArray[1][0] = ftOutline.points[index].x;	ctrlPtArray[1][1] = ftOutline.points[index].y;
		ctrlPtArray[2][0] = x;							ctrlPtArray[2][1] = y;

		evaluateCurve( 2);

		// process second curve
		ctrlPtArray[0][0] = x;							ctrlPtArray[0][1] = y;
		ctrlPtArray[1][0] = ftOutline.points[next].x;	ctrlPtArray[1][1] = ftOutline.points[next].y;
		ctrlPtArray[2][0] = ftOutline.points[next2].x;	ctrlPtArray[2][1] = ftOutline.points[next2].y;
		evaluateCurve( 2);

		return 2;
	}
}

int FTVectoriser::Cubic( const int index, const int first, const int last)
{
	int next = index + 1;
	int prev = index - 1;

	if( index == last)
		next = first;

	int next2 = next + 1;

	if( next == last)
		next2 = first;

	if( index == first)
		prev = last;

	ctrlPtArray[0][0] = ftOutline.points[prev].x;		ctrlPtArray[0][1] = ftOutline.points[prev].y;
	ctrlPtArray[1][0] = ftOutline.points[index].x;		ctrlPtArray[1][1] = ftOutline.points[index].y;
	ctrlPtArray[2][0] = ftOutline.points[next].x;		ctrlPtArray[2][1] = ftOutline.points[next].y;
	ctrlPtArray[3][0] = ftOutline.points[next2].x;		ctrlPtArray[3][1] = ftOutline.points[next2].y;

	evaluateCurve( 3);
	return 2;
}

// De Casteljau algorithm supplied by Jed Soane
void FTVectoriser::deCasteljau( const float t, const int n)
{
    //Calculating successive b(i)'s using de Casteljau algorithm.
    for( int i = 1; i <= n; i++)
        for( int k = 0; k <= (n - i); k++)
        {
			bValues[i][k][0] = (1 - t) * bValues[i - 1][k][0] + t * bValues[i - 1][k + 1][0];
			bValues[i][k][1] = (1 - t) * bValues[i - 1][k][1] + t * bValues[i - 1][k + 1][1];
		}

    //Specify next vertex to be included on curve
	contour->AddPoint( bValues[n][0][0], bValues[n][0][1]);
}

// De Casteljau algorithm supplied by Jed Soane
void FTVectoriser::evaluateCurve( const int n)
{
    // setting the b(0) equal to the control points
    for( int i = 0; i <= n; i++)
	{
		bValues[0][i][0] = ctrlPtArray[i][0];
		bValues[0][i][1] = ctrlPtArray[i][1];
    } //end for(i..)

    float t;            					//parameter for curve point calc. [0.0, 1.0]

    for( int m = 0; m <= (1 / kBSTEPSIZE); m++)
    {
    	t = m * kBSTEPSIZE;
        deCasteljau( t, n);  //calls to evaluate point on curve att.
    } //end for(m...)
}

void FTVectoriser::Output( double* data)
{
	int i = 0;

	for( int c= 0; c < contours(); ++c)
	{
		const FTContour* contour = contourList[c];

		for( int p = 0; p < contour->size(); ++p)
		{
			data[i] = static_cast<double>(contour->pointList[p].x / 64.0f); // is 64 correct?
			data[i + 1] = static_cast<double>(contour->pointList[p].y / 64.0f);
			data[i + 2] = 0.0; // static_cast<double>(contour->pointList[p].z / 64.0f);
			i += 3;
		}
	}
}
<|endoftext|>


<commit_before>#include	"FTVectoriser.h"
#include	"FTGL.h"

FTContour::FTContour()
:	kMAXPOINTS( 1000)
{
	pointList.reserve( kMAXPOINTS);
}

FTContour::~FTContour()
{
	pointList.clear();
}

void FTContour::AddPoint( const float x, const float y)
{
	ftPoint point( x, y, 0.0);

	// Eliminate duplicate points.
	if( ( pointList[pointList.size() - 1] != point) && pointList[0] != point)
	{
		pointList.push_back( point);
	}
}

FTVectoriser::FTVectoriser( const FT_Glyph glyph)
:	contourFlag(0),
	contour(0),
	kBSTEPSIZE( 0.2)

{
	FT_OutlineGlyph outline = (FT_OutlineGlyph)glyph;
	ftOutline = outline->outline;

	contourList.reserve( ftOutline.n_contours);
}

FTVectoriser::~FTVectoriser()
{
	for( int c = 0; c < contours(); ++c)
	{
		delete contourList[c];
	}

	contourList.clear();
}

int FTVectoriser::points()
{
	int s = 0;
	for( int c = 0; c < contours(); ++c)
	{
		s += contourList[c]->size();
	}

	return s;
}

bool FTVectoriser::Ingest()
{
	short first = 0;
	short last;
	const short cont = ftOutline.n_contours;

	for( short c = 0; c < cont; ++c)
	{
		contour = new FTContour;
		contourFlag = ftOutline.flags;
		last = ftOutline.contours[c];

		for( short p = first; p <= last; ++p)
		{
			switch( ftOutline.tags[p])
			{
				case FT_Curve_Tag_Conic:
					p += Conic( p, first, last);
					break;
				case FT_Curve_Tag_Cubic:
					p += Cubic( p, first, last);
					break;
				case FT_Curve_Tag_On:
				default:
 					contour->AddPoint( ftOutline.points[p].x, ftOutline.points[p].y);
			}
		}

		contourList.push_back( contour);
		first = last + 1;
	}

	return true;
}

int FTVectoriser::Conic( const int index, const int first, const int last)
{
	int next = index + 1;
	int prev = index - 1;

	if( index == last)
		next = first;

	if( index == first)
		prev = last;

	if( ftOutline.tags[next] != FT_Curve_Tag_Conic)
	{
		ctrlPtArray[0][0] = ftOutline.points[prev].x;	ctrlPtArray[0][1] = ftOutline.points[prev].y;
		ctrlPtArray[1][0] = ftOutline.points[index].x;	ctrlPtArray[1][1] = ftOutline.points[index].y;
		ctrlPtArray[2][0] = ftOutline.points[next].x;	ctrlPtArray[2][1] = ftOutline.points[next].y;

		evaluateCurve( 2);
		return 1;
	}
	else
	{
		int next2 = next + 1;
		if( next == last)
			next2 = first;

		//create a phantom point
		float x = ( ftOutline.points[index].x + ftOutline.points[next].x) / 2;
		float y = ( ftOutline.points[index].y + ftOutline.points[next].y) / 2;

		// process first curve
		ctrlPtArray[0][0] = ftOutline.points[prev].x;	ctrlPtArray[0][1] = ftOutline.points[prev].y;
		ctrlPtArray[1][0] = ftOutline.points[index].x;	ctrlPtArray[1][1] = ftOutline.points[index].y;
		ctrlPtArray[2][0] = x;							ctrlPtArray[2][1] = y;

		evaluateCurve( 2);

		// process second curve
		ctrlPtArray[0][0] = x;							ctrlPtArray[0][1] = y;
		ctrlPtArray[1][0] = ftOutline.points[next].x;	ctrlPtArray[1][1] = ftOutline.points[next].y;
		ctrlPtArray[2][0] = ftOutline.points[next2].x;	ctrlPtArray[2][1] = ftOutline.points[next2].y;
		evaluateCurve( 2);

		return 2;
	}
}

int FTVectoriser::Cubic( const int index, const int first, const int last)
{
	int next = index + 1;
	int prev = index - 1;

	if( index == last)
		next = first;

	int next2 = next + 1;

	if( next == last)
		next2 = first;

	if( index == first)
		prev = last;

	ctrlPtArray[0][0] = ftOutline.points[prev].x;		ctrlPtArray[0][1] = ftOutline.points[prev].y;
	ctrlPtArray[1][0] = ftOutline.points[index].x;		ctrlPtArray[1][1] = ftOutline.points[index].y;
	ctrlPtArray[2][0] = ftOutline.points[next].x;		ctrlPtArray[2][1] = ftOutline.points[next].y;
	ctrlPtArray[3][0] = ftOutline.points[next2].x;		ctrlPtArray[3][1] = ftOutline.points[next2].y;

	evaluateCurve( 3);
	return 2;
}

// De Casteljau algorithm contributed by Jed Soane
void FTVectoriser::deCasteljau( const float t, const int n)
{
    //Calculating successive b(i)'s using de Casteljau algorithm.
    for( int i = 1; i <= n; i++)
        for( int k = 0; k <= (n - i); k++)
        {
			bValues[i][k][0] = (1 - t) * bValues[i - 1][k][0] + t * bValues[i - 1][k + 1][0];
			bValues[i][k][1] = (1 - t) * bValues[i - 1][k][1] + t * bValues[i - 1][k + 1][1];
		}

    //Specify next vertex to be included on curve
	contour->AddPoint( bValues[n][0][0], bValues[n][0][1]);
}

// De Casteljau algorithm contributed by Jed Soane
void FTVectoriser::evaluateCurve( const int n)
{
    // setting the b(0) equal to the control points
    for( int i = 0; i <= n; i++)
	{
		bValues[0][i][0] = ctrlPtArray[i][0];
		bValues[0][i][1] = ctrlPtArray[i][1];
    }

    float t;            					//parameter for curve point calc. [0.0, 1.0]

    for( int m = 0; m <= ( 1 / kBSTEPSIZE); m++)
    {
    	t = m * kBSTEPSIZE;
        deCasteljau( t, n);  //calls to evaluate point on curve att.
    }
}

void FTVectoriser::Output( double* data)
{
	int i = 0;

	for( int c= 0; c < contours(); ++c)
	{
		const FTContour* contour = contourList[c];

		for( int p = 0; p < contour->size(); ++p)
		{
			data[i] = static_cast<double>(contour->pointList[p].x / 64.0f); // is 64 correct?
			data[i + 1] = static_cast<double>(contour->pointList[p].y / 64.0f);
			data[i + 2] = 0.0; // static_cast<double>(contour->pointList[p].z / 64.0f);
			i += 3;
		}
	}
}
<commit_msg>Added a test for an empty point list when adding points to a contour.<commit_after>#include	"FTVectoriser.h"
#include	"FTGL.h"

FTContour::FTContour()
:	kMAXPOINTS( 1000)
{
	pointList.reserve( kMAXPOINTS);
}

FTContour::~FTContour()
{
	pointList.clear();
}

void FTContour::AddPoint( const float x, const float y)
{
	ftPoint point( x, y, 0.0);

	// Eliminate duplicate points.
	if( pointList.empty() || ( pointList[pointList.size() - 1] != point && pointList[0] != point))
	{
		pointList.push_back( point);
	}
}

FTVectoriser::FTVectoriser( const FT_Glyph glyph)
:	contourFlag(0),
	contour(0),
	kBSTEPSIZE( 0.2)
{
	FT_OutlineGlyph outline = (FT_OutlineGlyph)glyph;
	ftOutline = outline->outline;

	contourList.reserve( ftOutline.n_contours);
}

FTVectoriser::~FTVectoriser()
{
	for( int c = 0; c < contours(); ++c)
	{
		delete contourList[c];
	}

	contourList.clear();
}

int FTVectoriser::points()
{
	int s = 0;
	for( int c = 0; c < contours(); ++c)
	{
		s += contourList[c]->size();
	}

	return s;
}

bool FTVectoriser::Ingest()
{
	short first = 0;
	short last;
	const short cont = ftOutline.n_contours;

	for( short c = 0; c < cont; ++c)
	{
		contour = new FTContour;
		contourFlag = ftOutline.flags;
		last = ftOutline.contours[c];

		for( short p = first; p <= last; ++p)
		{
			switch( ftOutline.tags[p])
			{
				case FT_Curve_Tag_Conic:
					p += Conic( p, first, last);
					break;
				case FT_Curve_Tag_Cubic:
					p += Cubic( p, first, last);
					break;
				case FT_Curve_Tag_On:
				default:
 					contour->AddPoint( ftOutline.points[p].x, ftOutline.points[p].y);
			}
		}

		contourList.push_back( contour);
		first = last + 1;
	}

	return true;
}

int FTVectoriser::Conic( const int index, const int first, const int last)
{
	int next = index + 1;
	int prev = index - 1;

	if( index == last)
		next = first;

	if( index == first)
		prev = last;

	if( ftOutline.tags[next] != FT_Curve_Tag_Conic)
	{
		ctrlPtArray[0][0] = ftOutline.points[prev].x;	ctrlPtArray[0][1] = ftOutline.points[prev].y;
		ctrlPtArray[1][0] = ftOutline.points[index].x;	ctrlPtArray[1][1] = ftOutline.points[index].y;
		ctrlPtArray[2][0] = ftOutline.points[next].x;	ctrlPtArray[2][1] = ftOutline.points[next].y;

		evaluateCurve( 2);
		return 1;
	}
	else
	{
		int next2 = next + 1;
		if( next == last)
			next2 = first;

		//create a phantom point
		float x = ( ftOutline.points[index].x + ftOutline.points[next].x) / 2;
		float y = ( ftOutline.points[index].y + ftOutline.points[next].y) / 2;

		// process first curve
		ctrlPtArray[0][0] = ftOutline.points[prev].x;	ctrlPtArray[0][1] = ftOutline.points[prev].y;
		ctrlPtArray[1][0] = ftOutline.points[index].x;	ctrlPtArray[1][1] = ftOutline.points[index].y;
		ctrlPtArray[2][0] = x;							ctrlPtArray[2][1] = y;

		evaluateCurve( 2);

		// process second curve
		ctrlPtArray[0][0] = x;							ctrlPtArray[0][1] = y;
		ctrlPtArray[1][0] = ftOutline.points[next].x;	ctrlPtArray[1][1] = ftOutline.points[next].y;
		ctrlPtArray[2][0] = ftOutline.points[next2].x;	ctrlPtArray[2][1] = ftOutline.points[next2].y;
		evaluateCurve( 2);

		return 2;
	}
}

int FTVectoriser::Cubic( const int index, const int first, const int last)
{
	int next = index + 1;
	int prev = index - 1;

	if( index == last)
		next = first;

	int next2 = next + 1;

	if( next == last)
		next2 = first;

	if( index == first)
		prev = last;

	ctrlPtArray[0][0] = ftOutline.points[prev].x;		ctrlPtArray[0][1] = ftOutline.points[prev].y;
	ctrlPtArray[1][0] = ftOutline.points[index].x;		ctrlPtArray[1][1] = ftOutline.points[index].y;
	ctrlPtArray[2][0] = ftOutline.points[next].x;		ctrlPtArray[2][1] = ftOutline.points[next].y;
	ctrlPtArray[3][0] = ftOutline.points[next2].x;		ctrlPtArray[3][1] = ftOutline.points[next2].y;

	evaluateCurve( 3);
	return 2;
}

// De Casteljau algorithm contributed by Jed Soane
void FTVectoriser::deCasteljau( const float t, const int n)
{
    //Calculating successive b(i)'s using de Casteljau algorithm.
    for( int i = 1; i <= n; i++)
        for( int k = 0; k <= (n - i); k++)
        {
			bValues[i][k][0] = (1 - t) * bValues[i - 1][k][0] + t * bValues[i - 1][k + 1][0];
			bValues[i][k][1] = (1 - t) * bValues[i - 1][k][1] + t * bValues[i - 1][k + 1][1];
		}

    //Specify next vertex to be included on curve
	contour->AddPoint( bValues[n][0][0], bValues[n][0][1]);
}

// De Casteljau algorithm contributed by Jed Soane
void FTVectoriser::evaluateCurve( const int n)
{
    // setting the b(0) equal to the control points
    for( int i = 0; i <= n; i++)
	{
		bValues[0][i][0] = ctrlPtArray[i][0];
		bValues[0][i][1] = ctrlPtArray[i][1];
    }

    float t;            					//parameter for curve point calc. [0.0, 1.0]

    for( int m = 0; m <= ( 1 / kBSTEPSIZE); m++)
    {
    	t = m * kBSTEPSIZE;
        deCasteljau( t, n);  //calls to evaluate point on curve att.
    }
}

void FTVectoriser::Output( double* data)
{
	int i = 0;

	for( int c= 0; c < contours(); ++c)
	{
		const FTContour* contour = contourList[c];

		for( int p = 0; p < contour->size(); ++p)
		{
			data[i] = static_cast<double>(contour->pointList[p].x / 64.0f); // is 64 correct?
			data[i + 1] = static_cast<double>(contour->pointList[p].y / 64.0f);
			data[i + 2] = 0.0; // static_cast<double>(contour->pointList[p].z / 64.0f);
			i += 3;
		}
	}
}
<|endoftext|>


<commit_before>/*
 * FileAppender.cpp
 *
 * Copyright 2000, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2000, Bastiaan Bakker. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#include <log4cpp/Portability.hh>
#include <log4cpp/OstringStream.hh>
#ifdef LOG4CPP_HAVE_IO_H
#    include <io.h>
#endif
#ifdef LOG4CPP_HAVE_UNISTD_H
#    include <unistd.h>
#endif

#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/Category.hh>

namespace log4cpp {

    FileAppender::FileAppender(const std::string& name,
                               const std::string& fileName) :
            LayoutAppender(name),
            _fileName(fileName) {
        _fd = ::open(_fileName.c_str(), O_CREAT | O_APPEND | O_WRONLY, 00644);
    }

    FileAppender::FileAppender(const std::string& name, int fd) :
        LayoutAppender(name),
        _fileName(""),
        _fd(fd) {
    }

    FileAppender::~FileAppender() {
        close();
    }

    void FileAppender::close() {
        ::close(_fd);
    }

    void FileAppender::_append(const LoggingEvent& event) {
        std::string message(_getLayout().format(event));
        if (!::write(_fd, message.data(), message.length())) {
            // XXX help! help!
        }
    }

    bool FileAppender::reopen() {
        if (_fileName != "") {
            int fd = ::open(_fileName.c_str(), O_CREAT | O_APPEND | O_WRONLY, 00644);
            if (fd < 0)
                return false;
            else {
                ::close(_fd);
                _fd = fd;
                return true;
            }
        } else {
            return true;
        }
    }
}
<commit_msg>only close the file descriptor if the file descriptor is not -1 set the file descriptor to -1 after closing it<commit_after>/*
 * FileAppender.cpp
 *
 * Copyright 2000, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2000, Bastiaan Bakker. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#include <log4cpp/Portability.hh>
#include <log4cpp/OstringStream.hh>
#ifdef LOG4CPP_HAVE_IO_H
#    include <io.h>
#endif
#ifdef LOG4CPP_HAVE_UNISTD_H
#    include <unistd.h>
#endif

#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/Category.hh>

namespace log4cpp {

    FileAppender::FileAppender(const std::string& name,
                               const std::string& fileName) :
            LayoutAppender(name),
            _fileName(fileName) {
        _fd = ::open(_fileName.c_str(), O_CREAT | O_APPEND | O_WRONLY, 00644);
    }

    FileAppender::FileAppender(const std::string& name, int fd) :
        LayoutAppender(name),
        _fileName(""),
        _fd(fd) {
    }

    FileAppender::~FileAppender() {
        close();
    }

    void FileAppender::close() {
        if (_fd!=-1) {
            ::close(_fd);
            _fd=-1;
        }
    }

    void FileAppender::_append(const LoggingEvent& event) {
        std::string message(_getLayout().format(event));
        if (!::write(_fd, message.data(), message.length())) {
            // XXX help! help!
        }
    }

    bool FileAppender::reopen() {
        if (_fileName != "") {
            int fd = ::open(_fileName.c_str(), O_CREAT | O_APPEND | O_WRONLY, 00644);
            if (fd < 0)
                return false;
            else {
	        if (_fd!=-1)
                    ::close(_fd);
                _fd = fd;
                return true;
            }
        } else {
            return true;
        }
    }
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifdef WNT
#include <windows.h>
#endif

#include <cstdlib>
#include <iostream>
#include <string>
#include <sal/types.h>
#include "cppunittester/protectorfactory.hxx"
#include "osl/module.h"
#include "osl/module.hxx"
#include "osl/thread.h"
#include "rtl/process.h"
#include "rtl/string.h"
#include "rtl/string.hxx"
#include "rtl/textcvt.h"
#include "rtl/ustring.hxx"
#include "sal/main.h"

#include "cppunit/CompilerOutputter.h"
#include "cppunit/Exception.h"
#include "cppunit/TestFailure.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestResultCollector.h"
#include "cppunit/TestRunner.h"
#include "cppunit/extensions/TestFactoryRegistry.h"
#include "cppunit/plugin/PlugInManager.h"
#include "cppunit/plugin/DynamicLibraryManagerException.h"
#include "cppunit/portability/Stream.h"

#include "boost/noncopyable.hpp"
#include "boost/ptr_container/ptr_vector.hpp"
#include <boost/scoped_array.hpp>
#include "boost/static_assert.hpp"

namespace {

void usageFailure() {
    std::cerr
        << ("Usage: cppunittester (--protector <shared-library-path>"
            " <function-symbol>)* <shared-library-path>")
        << std::endl;
    std::exit(EXIT_FAILURE);
}

rtl::OUString getArgument(sal_Int32 index) {
    rtl::OUString arg;
    rtl_getAppCommandArg(index, &arg.pData);
    return arg;
}

std::string convertLazy(rtl::OUString const & s16) {
    rtl::OString s8(rtl::OUStringToOString(s16, osl_getThreadTextEncoding()));
    BOOST_STATIC_ASSERT(sizeof (sal_Int32) <= sizeof (std::string::size_type));
        // ensure following cast is legitimate
    return std::string(
        s8.getStr(), static_cast< std::string::size_type >(s8.getLength()));
}

#if defined TIMETESTS
//Output how long each test took
class TimingListener
    : public CppUnit::TestListener
    , private boost::noncopyable
{
public:
    void startTest( CppUnit::Test *) SAL_OVERRIDE
    {
        m_nStartTime = osl_getGlobalTimer();
    }

    void endTest( CppUnit::Test *test ) SAL_OVERRIDE
    {
        sal_uInt32 nEndTime = osl_getGlobalTimer();
        std::cout << test->getName() << ": " << nEndTime-m_nStartTime
            << "ms" << std::endl;
    }

private:
    sal_uInt32 m_nStartTime;
};
#endif

#ifdef UNX
#include <stdlib.h>
// Setup an env variable so that temp file (or other) can
// have a usefull value to identify the source
class EyecatcherListener
    : public CppUnit::TestListener
    , private boost::noncopyable
{
public:
    void startTest( CppUnit::Test* test) SAL_OVERRIDE
    {
        boost::scoped_array<char> tn(new char [ test->getName().length() + 2 ]);
        strcpy(tn.get(), test->getName().c_str());
        int len = strlen(tn.get());
        for(int i = 0; i < len; i++)
        {
            if(!isalnum(tn[i]))
            {
                tn[i] = '_';
            }
        }
        tn[len] = '_';
        tn[len + 1] = 0;
        setenv("LO_TESTNAME", tn.get(), true);
    }

    void endTest( CppUnit::Test* /* test */ ) SAL_OVERRIDE
    {
    }
};
#endif

class LogFailuresAsTheyHappen : public CppUnit::TestListener
{
public:
    virtual void addFailure( const CppUnit::TestFailure &failure ) SAL_OVERRIDE
    {
        printFailureLocation( failure.sourceLine() );
        printFailedTestName( failure );
        printFailureMessage( failure );
    }

private:
    void printFailureLocation( const CppUnit::SourceLine &sourceLine )
    {
        if ( !sourceLine.isValid() )
            std::cerr << "unknown:0:";
        else
            std::cerr << sourceLine.fileName() << ":" << sourceLine.lineNumber() << ":";
    }

    void printFailedTestName( const CppUnit::TestFailure &failure )
    {
        std::cerr << failure.failedTestName() << std::endl;
    }

    void printFailureMessage( const CppUnit::TestFailure &failure )
    {
        std::cerr << failure.thrownException()->message().shortDescription() << std::endl;
        std::cerr << failure.thrownException()->message().details() << std::endl;
    }
};

//Allow the whole uniting testing framework to be run inside a "Protector"
//which knows about uno exceptions, so it can print the content of the
//exception before falling over and dying
class CPPUNIT_API ProtectedFixtureFunctor
    : public CppUnit::Functor
    , private boost::noncopyable
{
private:
    const std::string &testlib;
    const std::string &args;
    std::vector<CppUnit::Protector *> &protectors;
    CppUnit::TestResult &result;
public:
    ProtectedFixtureFunctor(const std::string& testlib_, const std::string &args_, std::vector<CppUnit::Protector*> &protectors_, CppUnit::TestResult &result_)
        : testlib(testlib_)
        , args(args_)
        , protectors(protectors_)
        , result(result_)
    {
    }
    bool run() const
    {
#ifdef DISABLE_DYNLOADING

        // NOTE: Running cppunit unit tests on iOS was something I did
        // only very early (several years ago) when starting porting
        // this stuff to iOS. The complicated mechanisms to do build
        // such unit test single executables have surely largely
        // bit-rotted or been semi-intentionally broken since. This
        // stuff here left for information only. --tml 2014.

        // For iOS cppunit plugins aren't really "plugins" (shared
        // libraries), but just static archives. In the real main
        // program of a cppunit app, which calls the lo_main() that
        // the SAL_IMPLEMENT_MAIN() below expands to, we specifically
        // call the initialize methods of the CppUnitTestPlugIns that
        // we statically link to the app executable.
#else
        CppUnit::PlugInManager manager;
        try {
            manager.load(testlib, args);
        } catch (const CppUnit::DynamicLibraryManagerException &e) {
            std::cerr << "DynamicLibraryManagerException: \"" << e.what() << "\"\n";
            return false;
        }
#endif
        CppUnit::TestRunner runner;
        runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());

        CppUnit::TestResultCollector collector;
        result.addListener(&collector);

        LogFailuresAsTheyHappen logger;
        result.addListener(&logger);

#ifdef TIMETESTS
        TimingListener timer;
        result.addListener(&timer);
#endif

#ifdef UNX
        EyecatcherListener eye;
        result.addListener(&eye);
#endif
        for (size_t i = 0; i < protectors.size(); ++i)
            result.pushProtector(protectors[i]);

        runner.run(result);

        for (size_t i = 0; i < protectors.size(); ++i)
            result.popProtector();

        CppUnit::CompilerOutputter outputter(&collector, CppUnit::stdCErr());
        outputter.setNoWrap();
        outputter.write();
        return collector.wasSuccessful();
    }
    virtual bool operator()() const SAL_OVERRIDE
    {
        return run();
    }
};

}

SAL_IMPLEMENT_MAIN() {
#ifdef WNT
    //Disable Dr-Watson in order to crash simply without popup dialogs under
    //windows
    DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
    SetErrorMode(SEM_NOGPFAULTERRORBOX|dwMode);
#ifdef _DEBUG // These functions are present only in the debgging runtime
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
    _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
    _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
#endif
#endif

    boost::ptr_vector<osl::Module> modules;
    std::vector<CppUnit::Protector *> protectors;
    CppUnit::TestResult result;
    std::string args;
    std::string testlib;
    sal_uInt32 index = 0;
    while (index < rtl_getAppCommandArgCount())
    {
        rtl::OUString arg = getArgument(index);
        if ( arg != "--protector" )
        {
            if (testlib.empty())
            {
                testlib = rtl::OUStringToOString(arg, osl_getThreadTextEncoding()).getStr();
                args += testlib;
            }
            else
            {
                args += ' ';
                args += rtl::OUStringToOString(arg, osl_getThreadTextEncoding()).getStr();
            }
            ++index;
            continue;
        }
        if (rtl_getAppCommandArgCount() - index < 3) {
            usageFailure();
        }
        rtl::OUString lib(getArgument(index + 1));
        rtl::OUString sym(getArgument(index + 2));
#ifndef DISABLE_DYNLOADING
        modules.push_back(new osl::Module(lib, SAL_LOADMODULE_GLOBAL));
        oslGenericFunction fn = modules.back().getFunctionSymbol(sym);
#else
        oslGenericFunction fn = 0;
        if (sym == "unoexceptionprotector")
            fn = (oslGenericFunction) unoexceptionprotector;
        else if (sym == "unobootstrapprotector")
            fn = (oslGenericFunction) unobootstrapprotector;
        else
        {
            std::cerr
                << "Only unoexceptionprotector or unobootstrapprotector protectors allowed"
                << std::endl;
            std::exit(EXIT_FAILURE);
        }
#endif
        CppUnit::Protector *protector = fn == 0
            ? 0
            : (*reinterpret_cast< cppunittester::ProtectorFactory * >(fn))();
        if (protector == 0) {
            std::cerr
                << "Failure instantiating protector \"" << convertLazy(lib)
                << "\", \"" << convertLazy(sym) << '"' << std::endl;
            std::exit(EXIT_FAILURE);
        }
        protectors.push_back(protector);
        index+=3;
    }

    ProtectedFixtureFunctor tests(testlib, args, protectors, result);
    bool ok = tests.run();

    return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Win32 - warn of extraordinary behaviour with LoadLibrary and long PATHs<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifdef WNT
#include <windows.h>
#endif

#include <cstdlib>
#include <iostream>
#include <string>
#include <sal/types.h>
#include "cppunittester/protectorfactory.hxx"
#include "osl/module.h"
#include "osl/module.hxx"
#include "osl/thread.h"
#include "rtl/process.h"
#include "rtl/string.h"
#include "rtl/string.hxx"
#include "rtl/textcvt.h"
#include "rtl/ustring.hxx"
#include "sal/main.h"

#include "cppunit/CompilerOutputter.h"
#include "cppunit/Exception.h"
#include "cppunit/TestFailure.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestResultCollector.h"
#include "cppunit/TestRunner.h"
#include "cppunit/extensions/TestFactoryRegistry.h"
#include "cppunit/plugin/PlugInManager.h"
#include "cppunit/plugin/DynamicLibraryManagerException.h"
#include "cppunit/portability/Stream.h"

#include "boost/noncopyable.hpp"
#include "boost/ptr_container/ptr_vector.hpp"
#include <boost/scoped_array.hpp>
#include "boost/static_assert.hpp"

namespace {

void usageFailure() {
    std::cerr
        << ("Usage: cppunittester (--protector <shared-library-path>"
            " <function-symbol>)* <shared-library-path>")
        << std::endl;
    std::exit(EXIT_FAILURE);
}

rtl::OUString getArgument(sal_Int32 index) {
    rtl::OUString arg;
    rtl_getAppCommandArg(index, &arg.pData);
    return arg;
}

std::string convertLazy(rtl::OUString const & s16) {
    rtl::OString s8(rtl::OUStringToOString(s16, osl_getThreadTextEncoding()));
    BOOST_STATIC_ASSERT(sizeof (sal_Int32) <= sizeof (std::string::size_type));
        // ensure following cast is legitimate
    return std::string(
        s8.getStr(), static_cast< std::string::size_type >(s8.getLength()));
}

#if defined TIMETESTS
//Output how long each test took
class TimingListener
    : public CppUnit::TestListener
    , private boost::noncopyable
{
public:
    void startTest( CppUnit::Test *) SAL_OVERRIDE
    {
        m_nStartTime = osl_getGlobalTimer();
    }

    void endTest( CppUnit::Test *test ) SAL_OVERRIDE
    {
        sal_uInt32 nEndTime = osl_getGlobalTimer();
        std::cout << test->getName() << ": " << nEndTime-m_nStartTime
            << "ms" << std::endl;
    }

private:
    sal_uInt32 m_nStartTime;
};
#endif

#ifdef UNX
#include <stdlib.h>
// Setup an env variable so that temp file (or other) can
// have a usefull value to identify the source
class EyecatcherListener
    : public CppUnit::TestListener
    , private boost::noncopyable
{
public:
    void startTest( CppUnit::Test* test) SAL_OVERRIDE
    {
        boost::scoped_array<char> tn(new char [ test->getName().length() + 2 ]);
        strcpy(tn.get(), test->getName().c_str());
        int len = strlen(tn.get());
        for(int i = 0; i < len; i++)
        {
            if(!isalnum(tn[i]))
            {
                tn[i] = '_';
            }
        }
        tn[len] = '_';
        tn[len + 1] = 0;
        setenv("LO_TESTNAME", tn.get(), true);
    }

    void endTest( CppUnit::Test* /* test */ ) SAL_OVERRIDE
    {
    }
};
#endif

class LogFailuresAsTheyHappen : public CppUnit::TestListener
{
public:
    virtual void addFailure( const CppUnit::TestFailure &failure ) SAL_OVERRIDE
    {
        printFailureLocation( failure.sourceLine() );
        printFailedTestName( failure );
        printFailureMessage( failure );
    }

private:
    void printFailureLocation( const CppUnit::SourceLine &sourceLine )
    {
        if ( !sourceLine.isValid() )
            std::cerr << "unknown:0:";
        else
            std::cerr << sourceLine.fileName() << ":" << sourceLine.lineNumber() << ":";
    }

    void printFailedTestName( const CppUnit::TestFailure &failure )
    {
        std::cerr << failure.failedTestName() << std::endl;
    }

    void printFailureMessage( const CppUnit::TestFailure &failure )
    {
        std::cerr << failure.thrownException()->message().shortDescription() << std::endl;
        std::cerr << failure.thrownException()->message().details() << std::endl;
    }
};

//Allow the whole uniting testing framework to be run inside a "Protector"
//which knows about uno exceptions, so it can print the content of the
//exception before falling over and dying
class CPPUNIT_API ProtectedFixtureFunctor
    : public CppUnit::Functor
    , private boost::noncopyable
{
private:
    const std::string &testlib;
    const std::string &args;
    std::vector<CppUnit::Protector *> &protectors;
    CppUnit::TestResult &result;
public:
    ProtectedFixtureFunctor(const std::string& testlib_, const std::string &args_, std::vector<CppUnit::Protector*> &protectors_, CppUnit::TestResult &result_)
        : testlib(testlib_)
        , args(args_)
        , protectors(protectors_)
        , result(result_)
    {
    }
    bool run() const
    {
#ifdef DISABLE_DYNLOADING

        // NOTE: Running cppunit unit tests on iOS was something I did
        // only very early (several years ago) when starting porting
        // this stuff to iOS. The complicated mechanisms to do build
        // such unit test single executables have surely largely
        // bit-rotted or been semi-intentionally broken since. This
        // stuff here left for information only. --tml 2014.

        // For iOS cppunit plugins aren't really "plugins" (shared
        // libraries), but just static archives. In the real main
        // program of a cppunit app, which calls the lo_main() that
        // the SAL_IMPLEMENT_MAIN() below expands to, we specifically
        // call the initialize methods of the CppUnitTestPlugIns that
        // we statically link to the app executable.
#else
        CppUnit::PlugInManager manager;
        try {
            manager.load(testlib, args);
        } catch (const CppUnit::DynamicLibraryManagerException &e) {
            std::cerr << "DynamicLibraryManagerException: \"" << e.what() << "\"\n";
#ifdef WIN32
            const char *pPath = getenv ("PATH");
            if (pPath && strlen (pPath) > 256)
            {
                std::cerr << "Windows has significant build problems with long PATH variables ";
                std::cerr << "please check your PATH variable and re-autogen.\n";
            }
#endif
            return false;
        }
#endif
        CppUnit::TestRunner runner;
        runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());

        CppUnit::TestResultCollector collector;
        result.addListener(&collector);

        LogFailuresAsTheyHappen logger;
        result.addListener(&logger);

#ifdef TIMETESTS
        TimingListener timer;
        result.addListener(&timer);
#endif

#ifdef UNX
        EyecatcherListener eye;
        result.addListener(&eye);
#endif
        for (size_t i = 0; i < protectors.size(); ++i)
            result.pushProtector(protectors[i]);

        runner.run(result);

        for (size_t i = 0; i < protectors.size(); ++i)
            result.popProtector();

        CppUnit::CompilerOutputter outputter(&collector, CppUnit::stdCErr());
        outputter.setNoWrap();
        outputter.write();
        return collector.wasSuccessful();
    }
    virtual bool operator()() const SAL_OVERRIDE
    {
        return run();
    }
};

}

SAL_IMPLEMENT_MAIN() {
#ifdef WNT
    //Disable Dr-Watson in order to crash simply without popup dialogs under
    //windows
    DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
    SetErrorMode(SEM_NOGPFAULTERRORBOX|dwMode);
#ifdef _DEBUG // These functions are present only in the debgging runtime
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
    _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
    _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
#endif
#endif

    boost::ptr_vector<osl::Module> modules;
    std::vector<CppUnit::Protector *> protectors;
    CppUnit::TestResult result;
    std::string args;
    std::string testlib;
    sal_uInt32 index = 0;
    while (index < rtl_getAppCommandArgCount())
    {
        rtl::OUString arg = getArgument(index);
        if ( arg != "--protector" )
        {
            if (testlib.empty())
            {
                testlib = rtl::OUStringToOString(arg, osl_getThreadTextEncoding()).getStr();
                args += testlib;
            }
            else
            {
                args += ' ';
                args += rtl::OUStringToOString(arg, osl_getThreadTextEncoding()).getStr();
            }
            ++index;
            continue;
        }
        if (rtl_getAppCommandArgCount() - index < 3) {
            usageFailure();
        }
        rtl::OUString lib(getArgument(index + 1));
        rtl::OUString sym(getArgument(index + 2));
#ifndef DISABLE_DYNLOADING
        modules.push_back(new osl::Module(lib, SAL_LOADMODULE_GLOBAL));
        oslGenericFunction fn = modules.back().getFunctionSymbol(sym);
#else
        oslGenericFunction fn = 0;
        if (sym == "unoexceptionprotector")
            fn = (oslGenericFunction) unoexceptionprotector;
        else if (sym == "unobootstrapprotector")
            fn = (oslGenericFunction) unobootstrapprotector;
        else
        {
            std::cerr
                << "Only unoexceptionprotector or unobootstrapprotector protectors allowed"
                << std::endl;
            std::exit(EXIT_FAILURE);
        }
#endif
        CppUnit::Protector *protector = fn == 0
            ? 0
            : (*reinterpret_cast< cppunittester::ProtectorFactory * >(fn))();
        if (protector == 0) {
            std::cerr
                << "Failure instantiating protector \"" << convertLazy(lib)
                << "\", \"" << convertLazy(sym) << '"' << std::endl;
            std::exit(EXIT_FAILURE);
        }
        protectors.push_back(protector);
        index+=3;
    }

    ProtectedFixtureFunctor tests(testlib, args, protectors, result);
    bool ok = tests.run();

    return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org.  If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/

#include "precompiled_sal.hxx"
#include "sal/config.h"

#include <cstdlib>
#include <iostream>

#include "preextstl.h"
#include "cppunit/CompilerOutputter.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestResultCollector.h"
#include "cppunit/TestRunner.h"
#include "cppunit/extensions/TestFactoryRegistry.h"
#include "cppunit/plugin/PlugInManager.h"
#include "cppunit/portability/Stream.h"
#include "postextstl.h"
#include "osl/thread.h"
#include "rtl/process.h"
#include "rtl/string.hxx"
#include "rtl/ustring.hxx"
#include "sal/main.h"

SAL_IMPLEMENT_MAIN() {
    if (rtl_getAppCommandArgCount() != 1) {
        std::cerr << "Usage: cppunittester <shared-library-path>" << std::endl;
        return EXIT_FAILURE;
    }
    rtl::OUString path;
    rtl_getAppCommandArg(0, &path.pData);
    CppUnit::PlugInManager manager;
    manager.load(
        rtl::OUStringToOString(path, osl_getThreadTextEncoding()).getStr());
    CppUnit::TestRunner runner;
    runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
    CppUnit::TestResult result;
    CppUnit::TestResultCollector collector;
    result.addListener(&collector);
    runner.run(result);
    CppUnit::CompilerOutputter(&collector, CppUnit::stdCErr()).write();
    return collector.wasSuccessful() ? EXIT_SUCCESS : EXIT_FAILURE;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>allow extra arguments<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org.  If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/

#include "precompiled_sal.hxx"
#include "sal/config.h"

#include <cstdlib>
#include <iostream>

#include "preextstl.h"
#include "cppunit/CompilerOutputter.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestResultCollector.h"
#include "cppunit/TestRunner.h"
#include "cppunit/extensions/TestFactoryRegistry.h"
#include "cppunit/plugin/PlugInManager.h"
#include "cppunit/portability/Stream.h"
#include "postextstl.h"
#include "osl/thread.h"
#include "rtl/process.h"
#include "rtl/string.hxx"
#include "rtl/ustring.hxx"
#include "sal/main.h"

SAL_IMPLEMENT_MAIN() {
    if (rtl_getAppCommandArgCount() < 1) {
        std::cerr << "Usage: cppunittester <shared-library-path>" << std::endl;
        return EXIT_FAILURE;
    }
    rtl::OUString path;
    rtl_getAppCommandArg(0, &path.pData);
    CppUnit::PlugInManager manager;
    manager.load(
        rtl::OUStringToOString(path, osl_getThreadTextEncoding()).getStr());
    CppUnit::TestRunner runner;
    runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
    CppUnit::TestResult result;
    CppUnit::TestResultCollector collector;
    result.addListener(&collector);
    runner.run(result);
    CppUnit::CompilerOutputter(&collector, CppUnit::stdCErr()).write();
    return collector.wasSuccessful() ? EXIT_SUCCESS : EXIT_FAILURE;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#include <thenet/socket_pool.hpp>
#include <thenet/connection_pool.hpp>
#include <thenet/client_socket.hpp>
#include <unistd.h>
#include <string>
#include <algorithm>

#include "socket_utils.hpp"

namespace
{

  class ListeningSocket : public the::net::Socket
  {
    public:
      ListeningSocket( int port, the::net::SocketPool& socket_pool )
        : Socket( socket( AF_INET, SOCK_STREAM, 0 ) )
        , m_socket_pool( socket_pool )
      {
        the::net::allow_address_reuse( *this );
        the::net::bind_to_port( port, *this );
        the::net::listen_with_queue_length( 5, *this );
      }

      virtual void handle_event() override
      {
        struct sockaddr_in address;
        socklen_t sin_size = sizeof( address );

        Socket::Pointer new_socket( new the::net::ClientSocket<the::net::SocketPool>(
              accept(fd, (struct sockaddr *) &address, &sin_size),
              m_socket_pool ) );

        set_non_blocking( *new_socket );
        m_socket_pool.on_new_socket( std::move( new_socket ) );
      }

    private:
      the::net::SocketPool& m_socket_pool;
  };

}

namespace the
{
namespace net
{

SocketPool::SocketPool( ConnectionPool& connection_pool )
  : m_connection_pool( connection_pool )
{
}

void
SocketPool::listen( int port )
{
  add_socket( Socket::Pointer( new ListeningSocket( port, *this ) ) );
}

void
SocketPool::on_data_available( Socket& socket, const char* data, size_t length )
{
  m_connection_pool.on_data_available( socket, data, length );
}

void
SocketPool::on_new_socket( Socket::Pointer&& socket )
{
  m_connection_pool.on_new_socket( *socket );
  add_socket( std::move( socket ) );
}

void
SocketPool::add_socket( Socket::Pointer&& socket )
{
  m_poll_descriptors.emplace_back( pollfd{ socket->fd, POLLIN, 0 } );
  m_sockets.emplace( std::make_pair( socket->fd, std::move( socket ) ) );
}

void
SocketPool::on_socket_lost( Socket& socket )
{
  m_connection_pool.on_socket_lost( socket );

  auto new_end( std::remove_if( begin( m_poll_descriptors ), end( m_poll_descriptors ),
        [ &socket ] ( pollfd& poll_descriptor )
        {
          return poll_descriptor.fd == socket.fd;
        } ) );
  m_poll_descriptors.erase( new_end, end( m_poll_descriptors ) );
  m_sockets.erase( socket.fd );
}

void
SocketPool::run_for( uint32_t run_for_milliseconds )
{
  if ( poll( &m_poll_descriptors[0], m_poll_descriptors.size(), run_for_milliseconds ) < 0 )
  {
    //todo: handle network error
    return;
  }

  for ( auto& poll_descriptor : m_poll_descriptors )
  {
    const bool no_event( !( poll_descriptor.revents & POLLIN) );
    if ( no_event )
    {
      continue;
    }
    m_sockets[ poll_descriptor.fd ]->handle_event();
  }

}

bool SocketPool::connect( const std::string& address, int port )
{
  const int new_socket( connect_socket( address, port ) );
  if ( new_socket < 0 )
  {
    return false;
  }

  Socket::Pointer connected_socket( new ClientSocket<SocketPool>( new_socket, *this ) );
  set_non_blocking( *connected_socket );
  on_new_socket( std::move( connected_socket ) );
  return true;
}

}
}

<commit_msg>rename listening socket to server socket<commit_after>#include <thenet/socket_pool.hpp>
#include <thenet/connection_pool.hpp>
#include <thenet/client_socket.hpp>
#include <unistd.h>
#include <string>
#include <algorithm>

#include "socket_utils.hpp"

namespace
{

  class ServerSocket : public the::net::Socket
  {
    public:
      ServerSocket( int port, the::net::SocketPool& socket_pool )
        : Socket( socket( AF_INET, SOCK_STREAM, 0 ) )
        , m_socket_pool( socket_pool )
      {
        the::net::allow_address_reuse( *this );
        the::net::bind_to_port( port, *this );
        the::net::listen_with_queue_length( 5, *this );
      }

      virtual void handle_event() override
      {
        struct sockaddr_in address;
        socklen_t sin_size = sizeof( address );

        Socket::Pointer new_socket( new the::net::ClientSocket<the::net::SocketPool>(
              accept(fd, (struct sockaddr *) &address, &sin_size),
              m_socket_pool ) );

        set_non_blocking( *new_socket );
        m_socket_pool.on_new_socket( std::move( new_socket ) );
      }

    private:
      the::net::SocketPool& m_socket_pool;
  };

}

namespace the
{
namespace net
{

SocketPool::SocketPool( ConnectionPool& connection_pool )
  : m_connection_pool( connection_pool )
{
}

void
SocketPool::listen( int port )
{
  add_socket( Socket::Pointer( new ServerSocket( port, *this ) ) );
}

void
SocketPool::on_data_available( Socket& socket, const char* data, size_t length )
{
  m_connection_pool.on_data_available( socket, data, length );
}

void
SocketPool::on_new_socket( Socket::Pointer&& socket )
{
  m_connection_pool.on_new_socket( *socket );
  add_socket( std::move( socket ) );
}

void
SocketPool::add_socket( Socket::Pointer&& socket )
{
  m_poll_descriptors.emplace_back( pollfd{ socket->fd, POLLIN, 0 } );
  m_sockets.emplace( std::make_pair( socket->fd, std::move( socket ) ) );
}

void
SocketPool::on_socket_lost( Socket& socket )
{
  m_connection_pool.on_socket_lost( socket );

  auto new_end( std::remove_if( begin( m_poll_descriptors ), end( m_poll_descriptors ),
        [ &socket ] ( pollfd& poll_descriptor )
        {
          return poll_descriptor.fd == socket.fd;
        } ) );
  m_poll_descriptors.erase( new_end, end( m_poll_descriptors ) );
  m_sockets.erase( socket.fd );
}

void
SocketPool::run_for( uint32_t run_for_milliseconds )
{
  if ( poll( &m_poll_descriptors[0], m_poll_descriptors.size(), run_for_milliseconds ) < 0 )
  {
    //todo: handle network error
    return;
  }

  for ( auto& poll_descriptor : m_poll_descriptors )
  {
    const bool no_event( !( poll_descriptor.revents & POLLIN) );
    if ( no_event )
    {
      continue;
    }
    m_sockets[ poll_descriptor.fd ]->handle_event();
  }

}

bool SocketPool::connect( const std::string& address, int port )
{
  const int new_socket( connect_socket( address, port ) );
  if ( new_socket < 0 )
  {
    return false;
  }

  Socket::Pointer connected_socket( new ClientSocket<SocketPool>( new_socket, *this ) );
  set_non_blocking( *connected_socket );
  on_new_socket( std::move( connected_socket ) );
  return true;
}

}
}

<|endoftext|>


<commit_before>#include <QtTest/QtTest>

#include "run-scenario.h"
#include "scenario-num.h"

class TestCFSM : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();
    void cleanupTestCase();
    void runScenario();
    void runScenario_data();

private:
    RunScenario *runner;
};

void TestCFSM::initTestCase()
{
    QCoreApplication::setOrganizationName(TEST_NAME);

    runner = new RunScenario();
}

void TestCFSM::cleanupTestCase()
{
    delete runner;
}

void TestCFSM::runScenario()
{
    QFETCH(int, scenario_number);
    QVERIFY(runner->runScenario(scenario_number) == 0);
}

void TestCFSM::runScenario_data()
{
    QTest::addColumn<int>("scenario_number");

    for(int i = 0; i < NUM_SCENARIOS; i++)
    {
        QString scenarioFilename =
            QString("scenario-%1.txt").arg(i, 2, 10, QChar('0'));
        QTest::newRow(scenarioFilename.toLatin1()) << i;
    }
}

QTEST_MAIN(TestCFSM)
#include "test-cfsm.moc"
<commit_msg>tests/CFSM: don't keep *runner around<commit_after>#include <QtTest/QtTest>

#include "run-scenario.h"
#include "scenario-num.h"

class TestCFSM : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();
    void runScenario();
    void runScenario_data();
};

void TestCFSM::initTestCase()
{
    QCoreApplication::setOrganizationName(TEST_NAME);
}

void TestCFSM::runScenario()
{
    QFETCH(int, scenario_number);

    RunScenario *runner;
    runner = new RunScenario();

    QVERIFY(runner->runScenario(scenario_number) == 0);

    delete runner;
}

void TestCFSM::runScenario_data()
{
    QTest::addColumn<int>("scenario_number");

    for(int i = 0; i < NUM_SCENARIOS; i++)
    {
        QString scenarioFilename =
            QString("scenario-%1.txt").arg(i, 2, 10, QChar('0'));
        QTest::newRow(scenarioFilename.toLatin1()) << i;
    }
}

QTEST_MAIN(TestCFSM)
#include "test-cfsm.moc"
<|endoftext|>