<commit_before>#ifndef CELL_AUTOMATA_ISING_SPIN
#define CELL_AUTOMATA_ISING_SPIN

#include <array>
#include <random>
#include <stdexcept>
#include <cmath>
#include "spin_base.hpp"

template<typename numerical_T, typename random_engine_T>
class Neuman_flip_spin : public Spin_base<int, 4>
{
    using numerical_type	= numerical_T;
    using random_engine_type	= random_engine_T;

  public:
    Neuman_flip_spin(state_type s, numerical_type& temp, numerical_type& perm,
		     numerical_type& spin_inter, random_engine_type& ran):
	Spin_base<int, 4>(s), tempreture(temp), magnetic_flux_density(perm),
	spin_interaction(spin_inter), random_engine(ran)
    {
	if(s != 1 && s != -1)
	    throw std::invalid_argument("Neuman flip spin state have to be 1 or -1.");

	typename
	    std::uniform_real_distribution<numerical_type>::param_type param_r(0.0, 1.0);
	dist_r01.param(param_r);

	typename
	    std::uniform_int_distribution<>::param_type param_i(0, 1);
	dist_i01.param(param_i);
    }

    virtual void set_partners(const partners_list_type& partners_list) override
    {
	partners = partners_list;
	return;
    }

    virtual void step() override
    {
	numerical_type energy_diff = after_flip_energy() - current_energy();
	if(energy_diff <= 0)
	    flip();
	else
	{
	    numerical_type flip_prob = std::exp(-tempreture * energy_diff);
	    if(dist_r01(random_engine) <= flip_prob)
		flip();
	}
	return;
    };

    void flip()
    {
	state *= -1;
	return;
    }

    numerical_type current_energy() const
    {
	numerical_type energy(0);
	for(auto elem_p : partners)
	    energy += elem_p->get();
	energy = (-spin_interaction * energy - magnetic_flux_density) * state;
	return energy;
    }

    numerical_type after_flip_energy() const
    {
	return -current_energy();
    }

    void initialize()
    {
	state = 2 * dist_i01(random_engine) - 1;
    }

  private:
    const numerical_type& tempreture, magnetic_flux_density, spin_interaction;
    random_engine_type& random_engine;
    std::uniform_real_distribution<numerical_type> dist_r01;
    std::uniform_int_distribution<> dist_i01;
};

#endif /* CELL_AUTOMATA_ISING_SPIN */
<commit_msg>edit fuc initialize() to virtual reset_state().<commit_after>#ifndef CELL_AUTOMATA_ISING_SPIN
#define CELL_AUTOMATA_ISING_SPIN

#include <array>
#include <random>
#include <stdexcept>
#include <cmath>
#include "spin_base.hpp"

template<typename numerical_T, typename random_engine_T>
class Neuman_flip_spin : public Spin_base<int, 4>
{
    using numerical_type	= numerical_T;
    using random_engine_type	= random_engine_T;

  public:
    Neuman_flip_spin(state_type s, numerical_type& temp, numerical_type& perm,
		     numerical_type& spin_inter, random_engine_type& ran):
	Spin_base<int, 4>(s), tempreture(temp), magnetic_flux_density(perm),
	spin_interaction(spin_inter), random_engine(ran)
    {
	if(s != 1 && s != -1)
	    throw std::invalid_argument("Neuman flip spin state have to be 1 or -1.");

	typename
	    std::uniform_real_distribution<numerical_type>::param_type param_r(0.0, 1.0);
	dist_r01.param(param_r);

	typename
	    std::uniform_int_distribution<>::param_type param_i(0, 1);
	dist_i01.param(param_i);
    }

    virtual void set_partners(const partners_list_type& partners_list) override
    {
	partners = partners_list;
	return;
    }

    virtual void step() override
    {
	numerical_type energy_diff = after_flip_energy() - current_energy();
	if(energy_diff <= 0)
	    flip();
	else
	{
	    numerical_type flip_prob = std::exp(-tempreture * energy_diff);
	    if(dist_r01(random_engine) <= flip_prob)
		flip();
	}
	return;
    };

    void flip()
    {
	state *= -1;
	return;
    }

    numerical_type current_energy() const
    {
	numerical_type energy(0);
	for(auto elem_p : partners)
	    energy += elem_p->get();
	energy = (-spin_interaction * energy - magnetic_flux_density) * state;
	return energy;
    }

    numerical_type after_flip_energy() const
    {
	return -current_energy();
    }

    virtual void reset_state() override
    {
	state = 2 * dist_i01(random_engine) - 1;
    }

  private:
    const numerical_type& tempreture, magnetic_flux_density, spin_interaction;
    random_engine_type& random_engine;
    std::uniform_real_distribution<numerical_type> dist_r01;
    std::uniform_int_distribution<> dist_i01;
};

#endif /* CELL_AUTOMATA_ISING_SPIN */
<|endoftext|>


<commit_before>#include "catch.hpp"

#include "StringToInteger.hpp"

TEST_CASE("String To Integer") {
  Solution s;

  SECTION("Normal tests") {
    REQUIRE(s.myAtoi("1") == 1);
  }

  SECTION("Normal tests 2") {
    REQUIRE(s.myAtoi("    010") == 10);
  }
}
<commit_msg>Update Problem 8 test case<commit_after>#include "catch.hpp"

#include "StringToInteger.hpp"

TEST_CASE("String To Integer") {
  Solution s;

  SECTION("Normal tests") {
    REQUIRE(s.myAtoi("1") == 1);
    REQUIRE(s.myAtoi("378") == 378);
    REQUIRE(s.myAtoi("-239") == -239);
    REQUIRE(s.myAtoi("+832") == 832);
  }

  SECTION("Boundary tests") {
    REQUIRE(s.myAtoi("-2147483648") == -2147483648);
    REQUIRE(s.myAtoi("-2147483649") == -2147483648);
    REQUIRE(s.myAtoi("2147483647") == 2147483647);
    REQUIRE(s.myAtoi("2147483648") == 2147483647);
  }

  SECTION("Format tests") {
    REQUIRE(s.myAtoi("asdfasf") == 0);
    REQUIRE(s.myAtoi("--124") == 0);
    REQUIRE(s.myAtoi("++4") == 0);
    REQUIRE(s.myAtoi("    +110?_+120__") == 110);
  }
}
<|endoftext|>


<commit_before>#include <cstring>

#include <Bull/Render/HardwareBuffer.hpp>
#include <Bull/Render/OpenGL.hpp>

namespace Bull
{
    void HardwareBuffer::bind(const HardwareBuffer& buffer)
    {
        ensureContext();
        gl::bindBuffer(buffer.m_type, buffer.m_id);
    }

    void HardwareBuffer::unbind(Type type)
    {
        ensureContext();
        gl::bindBuffer(type, 0);
    }

    HardwareBuffer::HardwareBuffer(Type type) :
        m_id(0),
        m_type(type)
    {
        /// Nothing
    }

    HardwareBuffer::~HardwareBuffer()
    {
        destroy();
    }

    bool HardwareBuffer::create(std::size_t size, Usage usage)
    {
        ensureContext();

        if(m_id)
        {
            destroy();
        }

        gl::genBuffers(1, &m_id);
        gl::bindBuffer(m_type, m_id);
        gl::bufferData(m_type, size, nullptr, usage);

        return true;
    }

    bool HardwareBuffer::fill(const void* data, std::size_t size, std::size_t offset, bool discard)
    {
        ensureContext();

        if(m_id)
        {
            gl::bindBuffer(m_type, m_id);

            /// It seems that glBufferSubData is more efficient than glMapBuffer with small buffers
            /// http://www.stevestreeting.com/2007/03/17/glmapbuffer-vs-glbuffersubdata-the-return/
            if(size < 32 * 1024)
            {
                gl::bufferSubData(m_type, offset, size, data);
            }
            else
            {
                unsigned char* ptr = reinterpret_cast<unsigned char*>(gl::mapBuffer(m_type, GL_WRITE_ONLY));

                if(!ptr)
                {
                    return false;
                }

                std::memcpy(ptr + offset, data, size);

                gl::unmapBuffer(m_type);
            }

            return true;
        }

        return false;
    }

    void HardwareBuffer::flush(bool keepMemory)
    {
        if(m_id)
        {
            ensureContext();

            gl::bindBuffer(m_type, m_id);
            if(!keepMemory)
            {
                m_size = 0;
            }

            int usage;
            gl::getBufferParameteriv(m_id, GL_BUFFER_USAGE, &usage);
            gl::bufferData(m_type, m_size, nullptr, usage);
        }
    }

    void HardwareBuffer::destroy()
    {
        if(m_id)
        {
            ensureContext();

            gl::deleteBuffers(1, &m_id);
        }
    }

    unsigned int HardwareBuffer::getSystemHandler() const
    {
        return m_id;
    }
}
<commit_msg>[Render/HardwareBuffer] Ensure context during destruction<commit_after>#include <cstring>

#include <Bull/Render/HardwareBuffer.hpp>
#include <Bull/Render/OpenGL.hpp>

namespace Bull
{
    void HardwareBuffer::bind(const HardwareBuffer& buffer)
    {
        ensureContext();
        gl::bindBuffer(buffer.m_type, buffer.m_id);
    }

    void HardwareBuffer::unbind(Type type)
    {
        ensureContext();
        gl::bindBuffer(type, 0);
    }

    HardwareBuffer::HardwareBuffer(Type type) :
        m_id(0),
        m_type(type)
    {
        /// Nothing
    }

    HardwareBuffer::~HardwareBuffer()
    {
        ensureContext();
        destroy();
    }

    bool HardwareBuffer::create(std::size_t size, Usage usage)
    {
        ensureContext();

        if(m_id)
        {
            destroy();
        }

        gl::genBuffers(1, &m_id);
        gl::bindBuffer(m_type, m_id);
        gl::bufferData(m_type, size, nullptr, usage);

        return true;
    }

    bool HardwareBuffer::fill(const void* data, std::size_t size, std::size_t offset, bool discard)
    {
        ensureContext();

        if(m_id)
        {
            gl::bindBuffer(m_type, m_id);

            /// It seems that glBufferSubData is more efficient than glMapBuffer with small buffers
            /// http://www.stevestreeting.com/2007/03/17/glmapbuffer-vs-glbuffersubdata-the-return/
            if(size < 32 * 1024)
            {
                gl::bufferSubData(m_type, offset, size, data);
            }
            else
            {
                unsigned char* ptr = reinterpret_cast<unsigned char*>(gl::mapBuffer(m_type, GL_WRITE_ONLY));

                if(!ptr)
                {
                    return false;
                }

                std::memcpy(ptr + offset, data, size);

                gl::unmapBuffer(m_type);
            }

            return true;
        }

        return false;
    }

    void HardwareBuffer::flush(bool keepMemory)
    {
        if(m_id)
        {
            ensureContext();

            gl::bindBuffer(m_type, m_id);
            if(!keepMemory)
            {
                m_size = 0;
            }

            int usage;
            gl::getBufferParameteriv(m_id, GL_BUFFER_USAGE, &usage);
            gl::bufferData(m_type, m_size, nullptr, usage);
        }
    }

    void HardwareBuffer::destroy()
    {
        if(m_id)
        {
            ensureContext();

            gl::deleteBuffers(1, &m_id);
        }
    }

    unsigned int HardwareBuffer::getSystemHandler() const
    {
        return m_id;
    }
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * tests/api/read_write_test.cpp
 *
 * Part of Project Thrill.
 *
 * Copyright (C) 2015 Alexander Noe <aleexnoe@gmail.com>
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#include <thrill/api/allgather.hpp>
#include <thrill/api/generate.hpp>
#include <thrill/api/generate_from_file.hpp>
#include <thrill/api/read_binary.hpp>
#include <thrill/api/read_lines.hpp>
#include <thrill/api/size.hpp>
#include <thrill/api/write_binary.hpp>
#include <thrill/api/write_lines.hpp>
#include <thrill/api/write_lines_many.hpp>
#include <thrill/common/logger.hpp>
#include <thrill/common/system_exception.hpp>

#include <gtest/gtest.h>

#include <dirent.h>
#include <glob.h>
#include <sys/stat.h>

#include <algorithm>
#include <cstdlib>
#include <functional>
#include <random>
#include <string>
#include <utility>
#include <vector>

using namespace thrill;
using thrill::api::Context;
using thrill::api::DIARef;

/*!
 * A class which creates a temporary directory in /tmp/ and returns it via
 * get(). When the object is destroyed the temporary directory is wiped
 * non-recursively.
 */
class TemporaryDirectory
{
public:
    //! Create a temporary directory, returns its name without trailing /.
    static std::string make_directory(
        const char* sample = "thrill-testsuite-") {

        std::string tmp_dir = std::string(sample) + "XXXXXX";
        // evil const_cast, but mkdtemp replaces the XXXXXX with something
        // unique. it also mkdirs.
        char* p = mkdtemp(const_cast<char*>(tmp_dir.c_str()));

        if (p == nullptr) {
            throw common::SystemException(
                      "Could create temporary directory " + tmp_dir, errno);
        }

        return tmp_dir;
    }

    //! wipe temporary directory NON RECURSIVELY!
    static void wipe_directory(const std::string& tmp_dir, bool do_rmdir) {
        DIR* d = opendir(tmp_dir.c_str());
        if (d == nullptr) {
            throw common::SystemException(
                      "Could open temporary directory " + tmp_dir, errno);
        }

        struct dirent* de, entry;
        while (readdir_r(d, &entry, &de) == 0 && de != nullptr) {
            // skip ".", "..", and also hidden files (don't create them).
            if (de->d_name[0] == '.') continue;

            std::string path = tmp_dir + "/" + de->d_name;
            int r = unlink(path.c_str());
            if (r != 0)
                sLOG1 << "Could not unlink temporary file " << path
                      << ": " << strerror(errno);
        }

        closedir(d);

        if (!do_rmdir) return;

        if (rmdir(tmp_dir.c_str()) != 0) {
            sLOG1 << "Could not unlink temporary directory " << tmp_dir
                  << ": " << strerror(errno);
        }
    }

    TemporaryDirectory()
        : dir_(make_directory())
    { }

    ~TemporaryDirectory() {
        wipe_directory(dir_, true);
    }

    //! non-copyable: delete copy-constructor
    TemporaryDirectory(const TemporaryDirectory&) = delete;
    //! non-copyable: delete assignment operator
    TemporaryDirectory& operator = (const TemporaryDirectory&) = delete;

    //! return the temporary directory name
    const std::string & get() const { return dir_; }

    //! wipe contents of directory
    void wipe() const {
        wipe_directory(dir_, false);
    }

protected:
    std::string dir_;
};

TEST(IO, ReadSingleFile) {
    std::function<void(Context&)> start_func =
        [](Context& ctx) {
            auto integers = ReadLines(ctx, "inputs/test1")
                            .Map([](const std::string& line) {
                                     return std::stoi(line);
                                 });

            std::vector<int> out_vec = integers.AllGather();

            int i = 1;
            for (int element : out_vec) {
                ASSERT_EQ(element, i++);
            }

            ASSERT_EQ(16u, out_vec.size());
        };

    api::RunLocalTests(start_func);
}

TEST(IO, ReadFolder) {
    std::function<void(Context&)> start_func =
        [](Context& ctx) {
            ASSERT_EQ(ReadLines(ctx, "inputs/read_folder/*").Size(), 20);
        };

    api::RunLocalTests(start_func);
}

TEST(IO, ReadPartOfFolderCompressed) {
    std::function<void(Context&)> start_func =
        [](Context& ctx) {
            // folder read_ints contains compressed and non-compressed files
            // with integers from 25 to 1 and a file 'donotread', which contains
            // non int-castable strings
            auto integers = ReadLines(ctx, "inputs/read_ints/read*")
                            .Map([](const std::string& line) {
                                     return std::stoi(line);
                                 });

            std::vector<int> out_vec = integers.AllGather();

            int i = 25;
            for (int element : out_vec) {
                ASSERT_EQ(element, i--);
            }

            ASSERT_EQ(25u, out_vec.size());
        };

    api::RunLocalTests(start_func);
}

TEST(IO, GenerateFromFileRandomIntegers) {
    api::RunSameThread(
        [](api::Context& ctx) {
            std::default_random_engine generator({ std::random_device()() });
            std::uniform_int_distribution<int> distribution(1000, 10000);

            size_t generate_size = distribution(generator);

            auto input = GenerateFromFile(
                ctx,
                "inputs/test1",
                [](const std::string& line) {
                    return std::stoi(line);
                },
                generate_size);

            size_t writer_size = 0;

            input.Map(
                [&writer_size](const int& item) {
                    // file contains ints between 1  and 16
                    // fails if wrong integer is generated
                    EXPECT_GE(item, 1);
                    EXPECT_GE(16, item);
                    writer_size++;
                    return std::to_string(item) + "\n";
                })
            .WriteLinesMany("outputs/out1_");

            // DIA contains as many elements as we wanted to generate
            ASSERT_EQ(generate_size, writer_size);
        });
}

TEST(IO, WriteBinaryPatternFormatter) {

    using WriteBinaryNode = api::WriteBinaryNode<int, int>;

    std::string str1 = WriteBinaryNode::make_path("test-$$$$-########", 42, 10);
    ASSERT_EQ("test-0042-00000010", str1);

    std::string str2 = WriteBinaryNode::make_path("test", 42, 10);
    ASSERT_EQ("test00420000000010", str2);
}

TEST(IO, GenerateIntegerWriteReadBinary) {
    TemporaryDirectory tmpdir;

    api::RunLocalTests(
        [&tmpdir](api::Context& ctx) {

            // wipe directory from last test
            if (ctx.my_rank() == 0) {
                tmpdir.wipe();
            }
            ctx.Barrier();

            // generate a dia of integers and write them to disk
            size_t generate_size = 32000;
            {
                auto dia = Generate(
                    ctx,
                    [](const size_t index) { return index + 42; },
                    generate_size);

                dia.WriteBinary(tmpdir.get() + "/IO.IntegerBinary",
                                16 * 1024);
            }
            ctx.Barrier();

            // read the integers from disk (collectively) and compare
            {
                auto dia = api::ReadBinary<size_t>(
                    ctx,
                    tmpdir.get() + "/IO.IntegerBinary*");

                std::vector<size_t> vec = dia.AllGather();

                ASSERT_EQ(generate_size, vec.size());
                // this is another action
                ASSERT_EQ(generate_size, dia.Size());

                for (size_t i = 0; i < vec.size(); ++i) {
                    ASSERT_EQ(42 + i, vec[i]);
                }
            }
        });
}

TEST(IO, GenerateIntegerWriteReadBinaryCompressed) {
    TemporaryDirectory tmpdir;

    api::RunLocalTests(
        [&tmpdir](api::Context& ctx) {

            // wipe directory from last test
            if (ctx.my_rank() == 0) {
                tmpdir.wipe();
            }
            ctx.Barrier();

            // generate a dia of integers and write them to disk
            size_t generate_size = 32000;
            {
                auto dia = Generate(
                    ctx,
                    [](const size_t index) { return index + 42; },
                    generate_size);

                dia.WriteBinary(tmpdir.get() + "/IO.IntegerBinary-$$$$-####.gz",
                                16 * 1024);
            }
            ctx.Barrier();

            // read the integers from disk (collectively) and compare
            {
                auto dia = api::ReadBinary<size_t>(
                    ctx,
                    tmpdir.get() + "/IO.IntegerBinary*");

                std::vector<size_t> vec = dia.AllGather();

                ASSERT_EQ(generate_size, vec.size());
                // this is another action
                ASSERT_EQ(generate_size, dia.Size());

                for (size_t i = 0; i < vec.size(); ++i) {
                    ASSERT_EQ(42 + i, vec[i]);
                }
            }
        });
}

// make weird test strings of different lengths
std::string test_string(size_t index) {
    return std::string('0' + index % 100, (index * index) % 20);
}

TEST(IO, GenerateStringWriteBinary) {
    TemporaryDirectory tmpdir;

    // use pairs for easier checking and stranger string sizes.
    using Item = std::pair<size_t, std::string>;

    api::RunLocalTests(
        [&tmpdir](api::Context& ctx) {

            // wipe directory from last test
            if (ctx.my_rank() == 0) {
                tmpdir.wipe();
            }
            ctx.Barrier();

            // generate a dia of string Items and write them to disk
            size_t generate_size = 32000;
            {
                auto dia = Generate(
                    ctx,
                    [](const size_t index) {
                        return Item(index, test_string(index));
                    },
                    generate_size);

                dia.WriteBinary(tmpdir.get() + "/IO.StringBinary",
                                16 * 1024);
            }
            ctx.Barrier();

            // read the Items from disk (collectively) and compare
            {
                auto dia = api::ReadBinary<Item>(
                    ctx,
                    tmpdir.get() + "/IO.StringBinary*");

                std::vector<Item> vec = dia.AllGather();

                ASSERT_EQ(generate_size, vec.size());
                // this is another action
                ASSERT_EQ(generate_size, dia.Size());

                for (size_t i = 0; i < vec.size(); ++i) {
                    ASSERT_EQ(Item(i, test_string(i)), vec[i]);
                }
            }
        });
}

TEST(IO, WriteAndReadBinaryEqualDIAS) {

    std::function<void(Context&)> start_func =
        [](Context& ctx) {
            if (ctx.my_rank() == 0) {
                // REVIEW(an): this MUST be removed.
                std::system("rm -r ./outputs/binary/*");
            }
            ctx.Barrier();

            auto integers = ReadLines(ctx, "inputs/test1")
                            .Map([](const std::string& line) {
                                     return std::stoi(line);
                                 });

            integers.WriteBinary("outputs/binary/output_");

            std::string path = "outputs/testsf.out";

            ctx.Barrier();

            auto integers2 = api::ReadBinary<int>(
                ctx, "./outputs/binary/*");

            integers2.Map(
                [](const int& item) {
                    return std::to_string(item);
                })
            .WriteLines(path);

            // Race condition as one worker might be finished while others are
            // still writing to output file.
            ctx.Barrier();

            std::ifstream file(path);
            size_t begin = file.tellg();
            file.seekg(0, std::ios::end);
            size_t end = file.tellg();
            ASSERT_EQ(end - begin, 39);
            file.seekg(0);
            for (int i = 1; i <= 16; i++) {
                std::string line;
                std::getline(file, line);
                ASSERT_EQ(std::stoi(line), i);
            }
        };

    api::RunLocalTests(start_func);
}

/******************************************************************************/
<commit_msg>use Tmpdir() instead of folder removal by system call<commit_after>/*******************************************************************************
 * tests/api/read_write_test.cpp
 *
 * Part of Project Thrill.
 *
 * Copyright (C) 2015 Alexander Noe <aleexnoe@gmail.com>
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#include <thrill/api/allgather.hpp>
#include <thrill/api/generate.hpp>
#include <thrill/api/generate_from_file.hpp>
#include <thrill/api/read_binary.hpp>
#include <thrill/api/read_lines.hpp>
#include <thrill/api/size.hpp>
#include <thrill/api/write_binary.hpp>
#include <thrill/api/write_lines.hpp>
#include <thrill/api/write_lines_many.hpp>
#include <thrill/common/logger.hpp>
#include <thrill/common/system_exception.hpp>

#include <gtest/gtest.h>

#include <dirent.h>
#include <glob.h>
#include <sys/stat.h>

#include <algorithm>
#include <cstdlib>
#include <functional>
#include <random>
#include <string>
#include <utility>
#include <vector>

using namespace thrill;
using thrill::api::Context;
using thrill::api::DIARef;

/*!
 * A class which creates a temporary directory in /tmp/ and returns it via
 * get(). When the object is destroyed the temporary directory is wiped
 * non-recursively.
 */
class TemporaryDirectory
{
public:
    //! Create a temporary directory, returns its name without trailing /.
    static std::string make_directory(
        const char* sample = "thrill-testsuite-") {

        std::string tmp_dir = std::string(sample) + "XXXXXX";
        // evil const_cast, but mkdtemp replaces the XXXXXX with something
        // unique. it also mkdirs.
        char* p = mkdtemp(const_cast<char*>(tmp_dir.c_str()));

        if (p == nullptr) {
            throw common::SystemException(
                      "Could create temporary directory " + tmp_dir, errno);
        }

        return tmp_dir;
    }

    //! wipe temporary directory NON RECURSIVELY!
    static void wipe_directory(const std::string& tmp_dir, bool do_rmdir) {
        DIR* d = opendir(tmp_dir.c_str());
        if (d == nullptr) {
            throw common::SystemException(
                      "Could open temporary directory " + tmp_dir, errno);
        }

        struct dirent* de, entry;
        while (readdir_r(d, &entry, &de) == 0 && de != nullptr) {
            // skip ".", "..", and also hidden files (don't create them).
            if (de->d_name[0] == '.') continue;

            std::string path = tmp_dir + "/" + de->d_name;
            int r = unlink(path.c_str());
            if (r != 0)
                sLOG1 << "Could not unlink temporary file " << path
                      << ": " << strerror(errno);
        }

        closedir(d);

        if (!do_rmdir) return;

        if (rmdir(tmp_dir.c_str()) != 0) {
            sLOG1 << "Could not unlink temporary directory " << tmp_dir
                  << ": " << strerror(errno);
        }
    }

    TemporaryDirectory()
        : dir_(make_directory())
    { }

    ~TemporaryDirectory() {
        wipe_directory(dir_, true);
    }

    //! non-copyable: delete copy-constructor
    TemporaryDirectory(const TemporaryDirectory&) = delete;
    //! non-copyable: delete assignment operator
    TemporaryDirectory& operator = (const TemporaryDirectory&) = delete;

    //! return the temporary directory name
    const std::string & get() const { return dir_; }

    //! wipe contents of directory
    void wipe() const {
        wipe_directory(dir_, false);
    }

protected:
    std::string dir_;
};

TEST(IO, ReadSingleFile) {
    std::function<void(Context&)> start_func =
        [](Context& ctx) {
            auto integers = ReadLines(ctx, "inputs/test1")
                            .Map([](const std::string& line) {
                                     return std::stoi(line);
                                 });

            std::vector<int> out_vec = integers.AllGather();

            int i = 1;
            for (int element : out_vec) {
                ASSERT_EQ(element, i++);
            }

            ASSERT_EQ(16u, out_vec.size());
        };

    api::RunLocalTests(start_func);
}

TEST(IO, ReadFolder) {
    std::function<void(Context&)> start_func =
        [](Context& ctx) {
            ASSERT_EQ(ReadLines(ctx, "inputs/read_folder/*").Size(), 20);
        };

    api::RunLocalTests(start_func);
}

TEST(IO, ReadPartOfFolderCompressed) {
    std::function<void(Context&)> start_func =
        [](Context& ctx) {
            // folder read_ints contains compressed and non-compressed files
            // with integers from 25 to 1 and a file 'donotread', which contains
            // non int-castable strings
            auto integers = ReadLines(ctx, "inputs/read_ints/read*")
                            .Map([](const std::string& line) {
                                     return std::stoi(line);
                                 });

            std::vector<int> out_vec = integers.AllGather();

            int i = 25;
            for (int element : out_vec) {
                ASSERT_EQ(element, i--);
            }

            ASSERT_EQ(25u, out_vec.size());
        };

    api::RunLocalTests(start_func);
}

TEST(IO, GenerateFromFileRandomIntegers) {
    api::RunSameThread(
        [](api::Context& ctx) {
            std::default_random_engine generator({ std::random_device()() });
            std::uniform_int_distribution<int> distribution(1000, 10000);

            size_t generate_size = distribution(generator);

            auto input = GenerateFromFile(
                ctx,
                "inputs/test1",
                [](const std::string& line) {
                    return std::stoi(line);
                },
                generate_size);

            size_t writer_size = 0;

            input.Map(
                [&writer_size](const int& item) {
                    // file contains ints between 1  and 16
                    // fails if wrong integer is generated
                    EXPECT_GE(item, 1);
                    EXPECT_GE(16, item);
                    writer_size++;
                    return std::to_string(item) + "\n";
                })
            .WriteLinesMany("outputs/out1_");

            // DIA contains as many elements as we wanted to generate
            ASSERT_EQ(generate_size, writer_size);
        });
}

TEST(IO, WriteBinaryPatternFormatter) {

    using WriteBinaryNode = api::WriteBinaryNode<int, int>;

    std::string str1 = WriteBinaryNode::make_path("test-$$$$-########", 42, 10);
    ASSERT_EQ("test-0042-00000010", str1);

    std::string str2 = WriteBinaryNode::make_path("test", 42, 10);
    ASSERT_EQ("test00420000000010", str2);
}

TEST(IO, GenerateIntegerWriteReadBinary) {
    TemporaryDirectory tmpdir;

    api::RunLocalTests(
        [&tmpdir](api::Context& ctx) {

            // wipe directory from last test
            if (ctx.my_rank() == 0) {
                tmpdir.wipe();
            }
            ctx.Barrier();

            // generate a dia of integers and write them to disk
            size_t generate_size = 32000;
            {
                auto dia = Generate(
                    ctx,
                    [](const size_t index) { return index + 42; },
                    generate_size);

                dia.WriteBinary(tmpdir.get() + "/IO.IntegerBinary",
                                16 * 1024);
            }
            ctx.Barrier();

            // read the integers from disk (collectively) and compare
            {
                auto dia = api::ReadBinary<size_t>(
                    ctx,
                    tmpdir.get() + "/IO.IntegerBinary*");

                std::vector<size_t> vec = dia.AllGather();

                ASSERT_EQ(generate_size, vec.size());
                // this is another action
                ASSERT_EQ(generate_size, dia.Size());

                for (size_t i = 0; i < vec.size(); ++i) {
                    ASSERT_EQ(42 + i, vec[i]);
                }
            }
        });
}

TEST(IO, GenerateIntegerWriteReadBinaryCompressed) {
    TemporaryDirectory tmpdir;

    api::RunLocalTests(
        [&tmpdir](api::Context& ctx) {

            // wipe directory from last test
            if (ctx.my_rank() == 0) {
                tmpdir.wipe();
            }
            ctx.Barrier();

            // generate a dia of integers and write them to disk
            size_t generate_size = 32000;
            {
                auto dia = Generate(
                    ctx,
                    [](const size_t index) { return index + 42; },
                    generate_size);

                dia.WriteBinary(tmpdir.get() + "/IO.IntegerBinary-$$$$-####.gz",
                                16 * 1024);
            }
            ctx.Barrier();

            // read the integers from disk (collectively) and compare
            {
                auto dia = api::ReadBinary<size_t>(
                    ctx,
                    tmpdir.get() + "/IO.IntegerBinary*");

                std::vector<size_t> vec = dia.AllGather();

                ASSERT_EQ(generate_size, vec.size());
                // this is another action
                ASSERT_EQ(generate_size, dia.Size());

                for (size_t i = 0; i < vec.size(); ++i) {
                    ASSERT_EQ(42 + i, vec[i]);
                }
            }
        });
}

// make weird test strings of different lengths
std::string test_string(size_t index) {
    return std::string('0' + index % 100, (index * index) % 20);
}

TEST(IO, GenerateStringWriteBinary) {

    TemporaryDirectory tmpdir;

    // use pairs for easier checking and stranger string sizes.
    using Item = std::pair<size_t, std::string>;

    api::RunLocalTests(
        [&tmpdir](api::Context& ctx) {

            // wipe directory from last test
            if (ctx.my_rank() == 0) {
                tmpdir.wipe();
            }
            ctx.Barrier();

            // generate a dia of string Items and write them to disk
            size_t generate_size = 32000;
            {
                auto dia = Generate(
                    ctx,
                    [](const size_t index) {
                        return Item(index, test_string(index));
                    },
                    generate_size);

                dia.WriteBinary(tmpdir.get() + "/IO.StringBinary",
                                16 * 1024);
            }
            ctx.Barrier();

            // read the Items from disk (collectively) and compare
            {
                auto dia = api::ReadBinary<Item>(
                    ctx,
                    tmpdir.get() + "/IO.StringBinary*");

                std::vector<Item> vec = dia.AllGather();

                ASSERT_EQ(generate_size, vec.size());
                // this is another action
                ASSERT_EQ(generate_size, dia.Size());

                for (size_t i = 0; i < vec.size(); ++i) {
                    ASSERT_EQ(Item(i, test_string(i)), vec[i]);
                }
            }
        });
}

TEST(IO, WriteAndReadBinaryEqualDIAS) {
    TemporaryDirectory tmpdir;

    std::function<void(Context&)> start_func =
        [&tmpdir](Context& ctx) {
            if (ctx.my_rank() == 0) {
                tmpdir.wipe();
            }
            ctx.Barrier();

            auto integers = ReadLines(ctx, "inputs/test1")
                            .Map([](const std::string& line) {
                                     return std::stoi(line);
                                 });

            integers.WriteBinary(tmpdir.get() + "/output_");

            std::string path = "outputs/testsf.out";

            ctx.Barrier();

            auto integers2 = api::ReadBinary<int>(
                ctx, tmpdir.get() + "/*");

            integers2.Map(
                [](const int& item) {
                    return std::to_string(item);
                })
            .WriteLines(path);

            // Race condition as one worker might be finished while others are
            // still writing to output file.
            ctx.Barrier();

            std::ifstream file(path);
            size_t begin = file.tellg();
            file.seekg(0, std::ios::end);
            size_t end = file.tellg();
            ASSERT_EQ(end - begin, 39);
            file.seekg(0);
            for (int i = 1; i <= 16; i++) {
                std::string line;
                std::getline(file, line);
                ASSERT_EQ(std::stoi(line), i);
            }
        };

    api::RunLocalTests(start_func);
}

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


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

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

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

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

#include "Inspector.h"

#include "AssetTree.h"
#include "ComboBox.h"

#include "../Models/PropertyModel.h"
#include "../Models/EnumerationModel.h"

DC_BEGIN_COMPOSER

namespace Ui {

void qDeleteLayout( QLayout* layout )
{
	if( !layout ) {
		return;
	}

	QLayoutItem* child = NULL;

	while( (child = layout->takeAt(0)) != 0 ) {
		delete child->widget();
		delete child;
	}

	delete layout;
}

// ** Inspector::Inspector
Inspector::Inspector( QWidget* parent ) : QWidget( parent ), m_layout( NULL ), m_mapper( NULL )
{

}

// ** Inspector::setModel
void Inspector::setModel( PropertyModelQPtr value )
{
	// Set the model
	m_model = value;

	// Destroy old layout & mapper
	qDeleteLayout( m_layout ); m_layout = NULL;
	delete m_mapper; m_mapper = NULL;

	// Return if the model is not valid
	if( !m_model.get() ) {
		return;
	}

	// Create the mapper.
	m_mapper = new QDataWidgetMapper( this );
	m_mapper->setModel( m_model.get() );

	// Create root layout.
	m_layout = new QFormLayout( this );

	// Construct property widgets.
	for( s32 i = 0, n = m_model->propertyCount(); i < n; i++ ) {
		// Get the property type & name
		QString type = m_model->propertyType( i );
		QString name = m_model->propertyName( i );

		// Construct the widget according to the type
		QWidget* widget = NULL;

		if( type == "Scene::ImageWPtr" ) {
        #if 0
			widget = new AssetSelector( Scene::Asset::Image );
			connect( widget, SIGNAL(valueChanged()), m_mapper, SLOT(submit()) );
        #else
            DC_NOT_IMPLEMENTED
        #endif
		}
		else if( type == "Scene::RenderingMode" ) {
			widget = new RenderingModeComboBox;
		}
		else if( type == "Scene::Material::Model" ) {
			widget = new LightingComboBox;
		}
		else {
			qWarning() << "Property" << name << "has unhnadled type" << type;
			continue;
		}

		// Add widget
		m_layout->addRow( name, widget );
		m_mapper->addMapping( widget, i );
	}

	// Finish construction
	m_mapper->toFirst();
	m_mapper->setSubmitPolicy( QDataWidgetMapper::AutoSubmit );
}

} // namespace Ui

DC_END_COMPOSER<commit_msg>Removed: temporary removed code<commit_after>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

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

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

#include "Inspector.h"

#include "AssetTree.h"
#include "ComboBox.h"

#include "../Models/PropertyModel.h"
#include "../Models/EnumerationModel.h"

DC_BEGIN_COMPOSER

namespace Ui {

void qDeleteLayout( QLayout* layout )
{
	if( !layout ) {
		return;
	}

	QLayoutItem* child = NULL;

	while( (child = layout->takeAt(0)) != 0 ) {
		delete child->widget();
		delete child;
	}

	delete layout;
}

// ** Inspector::Inspector
Inspector::Inspector( QWidget* parent ) : QWidget( parent ), m_layout( NULL ), m_mapper( NULL )
{

}

// ** Inspector::setModel
void Inspector::setModel( PropertyModelQPtr value )
{
	// Set the model
	m_model = value;

	// Destroy old layout & mapper
	qDeleteLayout( m_layout ); m_layout = NULL;
	delete m_mapper; m_mapper = NULL;

	// Return if the model is not valid
	if( !m_model.get() ) {
		return;
	}

	// Create the mapper.
	m_mapper = new QDataWidgetMapper( this );
	m_mapper->setModel( m_model.get() );

	// Create root layout.
	m_layout = new QFormLayout( this );

	// Construct property widgets.
	for( s32 i = 0, n = m_model->propertyCount(); i < n; i++ ) {
		// Get the property type & name
		QString type = m_model->propertyType( i );
		QString name = m_model->propertyName( i );

		// Construct the widget according to the type
		QWidget* widget = NULL;

		if( type == "Scene::ImageWPtr" ) {
			widget = new AssetSelector( Scene::AssetType::fromClass<Scene::Image>().bit(), this );
			connect( widget, SIGNAL(valueChanged()), m_mapper, SLOT(submit()) );
		}
		else if( type == "Scene::RenderingMode" ) {
			widget = new RenderingModeComboBox;
		}
		else if( type == "Scene::Material::Model" ) {
			widget = new LightingComboBox;
		}
		else {
			qWarning() << "Property" << name << "has unhnadled type" << type;
			continue;
		}

		// Add widget
		m_layout->addRow( name, widget );
		m_mapper->addMapping( widget, i );
	}

	// Finish construction
	m_mapper->toFirst();
	m_mapper->setSubmitPolicy( QDataWidgetMapper::AutoSubmit );
}

} // namespace Ui

DC_END_COMPOSER<|endoftext|>


<commit_before>using namespace Cooper;

class VideoController : public Controller {
private:
	std::map <std::string, void(VideoController::*)()> _methods;

public:

	void _callAction(std::string name) {
		if (this->_methods.find(name) != this->_methods.end()) {
			(*this.*_methods[name])();
		} else {
			throw Cooper::Exceptions::NotFoundException();
		}
	}

	VideoController() {
		this->_methods["upload"] = &VideoController::ajaxUplaodAction;
		this->_methods["add"] = &VideoController::addAction;
	}

	void ajaxUplaodAction() {
		UserService us = UserService();
		if (!us.isLogined()) this->redirect("user", "login");

		VideoService vs = VideoService();
		vs.upload(us.getUser());
	}

	void addAction() {
		Template tpl("video/add");
		std::cout << tpl.render();
	}
};<commit_msg>Controller tpl support<commit_after>using namespace Cooper;

class VideoController : public Controller {
private:
	std::map <std::string, void(VideoController::*)()> _methods;

public:

	void _callAction(std::string name) {
		if (this->_methods.find(name) != this->_methods.end()) {
			(*this.*_methods[name])();
		} else {
			throw Cooper::Exceptions::NotFoundException();
		}
	}

	VideoController() {
		this->_methods["upload"] = &VideoController::ajaxUplaodAction;
		this->_methods["add"] = &VideoController::addAction;
	}

	void ajaxUplaodAction() {
		UserService us = UserService();
		if (!us.isLogined()) this->redirect("user", "login");

		VideoService vs = VideoService();
		vs.upload(us.getUser());
	}

	void addAction() {
		Template tpl("video/add");
		std::cout << tpl.render();
	}

	void indexAction(){

	}

	void likesAction(){
		std::map<std::string, std::string> data;
		// sample data
		data["id"] = "50";
		data["title"] = "Lorem ipsum";
		data["image"] = "img/temp/1.jpg";

		Template tpl("video/likes");

		for (int i = 0; i < 3; i++) {
			Template line("main/_index-video-line");

			for (int i = 0; i < 3; i++) {
				Template box("main/_index-video-box");

				box.set("id", data["id"]);
				box.set("title", data["title"]);
				box.set("image", data["image"]);

				line.add("videoline", box.render(false));
			}

			tpl.add("content", line.render(false));
		}

		std::cout << tpl.render();
	}

	void likeAction(){

	}

	void recommendAction(){
		std::map<std::string, std::string> data;
		// sample data
		data["id"] = "50";
		data["title"] = "Lorem ipsum";
		data["image"] = "img/temp/1.jpg";

		Template tpl("video/recomend");

		for (int i = 0; i < 3; i++) {
			Template line("main/_index-video-line");

			for (int i = 0; i < 3; i++) {
				Template box("main/_index-video-box");

				box.set("id", data["id"]);
				box.set("title", data["title"]);
				box.set("image", data["image"]);

				line.add("videoline", box.render(false));
			}

			tpl.add("content", line.render(false));
		}

		std::cout << tpl.render();
	}
};<|endoftext|>


<commit_before>#include "CgStr.hpp"
#include "output.hpp"
#include "MultiTuProcessor.hpp"
#include "annotate.hpp"
#include "cgWrappers.hpp"
#include "config.hpp"
#include "xref.hpp"
#include "debug.hpp"

#include <climits>
#include <cstring>
#include <iostream>
#include <string>

using namespace synth;

static const unsigned kMaxRefRecursion = 16;

namespace {

struct FileState {
    HighlightedFile& hlFile;
    MultiTuProcessor& multiTuProcessor;
};

} // anonymous namespace

static bool isTypeKind(CXCursorKind k)
{
    SYNTH_DISCLANGWARN_BEGIN("-Wswitch-enum")
    switch (k) {
        case CXCursor_ClassDecl:
        case CXCursor_ClassTemplate:
        case CXCursor_ClassTemplatePartialSpecialization:
        case CXCursor_StructDecl:
        case CXCursor_UnionDecl:
        case CXCursor_EnumDecl:
        case CXCursor_TypedefDecl:
        case CXCursor_ObjCInterfaceDecl:
        case CXCursor_ObjCCategoryDecl:
        case CXCursor_ObjCProtocolDecl:
        case CXCursor_ObjCImplementationDecl:
        case CXCursor_TemplateTypeParameter:
        case CXCursor_TemplateTemplateParameter:
        case CXCursor_TypeAliasDecl:
        case CXCursor_TypeAliasTemplateDecl:
        case CXCursor_TypeRef:
        case CXCursor_ObjCSuperClassRef:
        case CXCursor_ObjCProtocolRef:
        case CXCursor_ObjCClassRef:
        case CXCursor_CXXBaseSpecifier:
            return true;

        default:
            return false;
    }
    SYNTH_DISCLANGWARN_END
}

static TokenAttributes getVarTokenAttributes(CXCursor cur)
{
    if (clang_getCursorLinkage(cur) == CXLinkage_NoLinkage)
        return TokenAttributes::varLocal;
    if (clang_getCXXAccessSpecifier(cur) == CX_CXXInvalidAccessSpecifier)
        return TokenAttributes::varGlobal;
    if (clang_Cursor_getStorageClass(cur) == CX_SC_Static)
        return TokenAttributes::varStaticMember;
    return TokenAttributes::varNonstaticMember;
}

static TokenAttributes getIntCssClasses(CXToken tok, CXTranslationUnit tu)
{
    std::string sp = CgStr(clang_getTokenSpelling(tu, tok)).gets();
    if (!sp.empty()) {
        if (sp.size() >= 2 && sp[0] == '0') {
            if (sp[1] == 'x' || sp[1] == 'X')
                return TokenAttributes::litNumIntHex;
            if (sp[1] == 'b' || sp[1] == 'B')
                return TokenAttributes::litNumIntBin;
            return TokenAttributes::litNumIntOct;
        }
        char suffix = sp[sp.size() - 1];
        if (suffix == 'l' || suffix == 'L')
            return TokenAttributes::litNumIntDecLong;
    }
    return TokenAttributes::litNum;
}

static bool startsWith(std::string const& s, std::string const& p) {
    return s.compare(0, p.size(), p) == 0;
}

static bool isBuiltinTypeKw(std::string const& t) {
    return startsWith(t, "unsigned ")
        || t == "unsigned"
        || startsWith(t, "signed ")
        || t == "signed"
        || startsWith(t, "short ")
        || t == "short"
        || startsWith(t, "long ")
        || t == "long"
        || t == "int"
        || t == "float"
        || t == "double"
        || t == "bool"
        || t == "char"
        || t == "char16_t"
        || t == "char32_t"
        || t == "wchar_t";
}

static TokenAttributes getTokenAttributes(
    CXToken tok, CXCursor cur, CXTranslationUnit tu, unsigned recursionDepth = 0)
{
    CXCursorKind k = clang_getCursorKind(cur);
    CXTokenKind tk = clang_getTokenKind(tok);
    if (clang_isPreprocessing(k)) {
        if (k == CXCursor_InclusionDirective) {
            CgStr spelling = clang_getTokenSpelling(tu, tok);
            if (std::strcmp(spelling.gets(), "include") != 0
                    && std::strcmp(spelling.gets(), "#") != 0
            ) {
                return TokenAttributes::preIncludeFile;
            }
        }
        return TokenAttributes::pre;
    }

    switch (tk) {
        case CXToken_Punctuation:
            if (k == CXCursor_BinaryOperator || k == CXCursor_UnaryOperator)
                return TokenAttributes::op;
            return TokenAttributes::punct;

        case CXToken_Comment:
            return TokenAttributes::cmmt;

        case CXToken_Literal:
            SYNTH_DISCLANGWARN_BEGIN("-Wswitch-enum")
            switch (k) {
                case CXCursor_ObjCStringLiteral:
                case CXCursor_StringLiteral:
                    return TokenAttributes::litStr;
                case CXCursor_CharacterLiteral:
                    return TokenAttributes::litChr;
                case CXCursor_FloatingLiteral:
                    return TokenAttributes::litNumFlt;
                case CXCursor_IntegerLiteral:
                    return getIntCssClasses(tok, tu);
                case CXCursor_ImaginaryLiteral:
                    return TokenAttributes::litNum;
                default:
                    return TokenAttributes::lit;
            }
            SYNTH_DISCLANGWARN_END

        case CXToken_Keyword: {
            if (k == CXCursor_BinaryOperator || k == CXCursor_UnaryOperator)
                return TokenAttributes::opWord;
            if (k == CXCursor_CXXNullPtrLiteralExpr
                || k == CXCursor_CXXBoolLiteralExpr
                || k == CXCursor_ObjCBoolLiteralExpr
            ) {
                return TokenAttributes::litKw;
            }
            std::string sp = CgStr(clang_getTokenSpelling(tu, tok)).gets();
            if (k == CXCursor_TypeRef || isBuiltinTypeKw(sp))
                return TokenAttributes::tyBuiltin;
            if (clang_isDeclaration(k))
                return TokenAttributes::kwDecl;
            return TokenAttributes::kw;
        }

        case CXToken_Identifier:
            if (isTypeKind(k))
                return TokenAttributes::ty;
            SYNTH_DISCLANGWARN_BEGIN("-Wswitch-enum")
            switch (k) {
                case CXCursor_MemberRef:
                case CXCursor_DeclRefExpr:
                case CXCursor_MemberRefExpr:
                case CXCursor_UsingDeclaration:
                case CXCursor_TemplateRef: {
                    CXCursor refd = clang_getCursorReferenced(cur);
                    bool selfRef = clang_equalCursors(cur, refd);
                    bool recErr = recursionDepth > kMaxRefRecursion;
                    if (selfRef || recErr) {
                        CgStr kindSp(clang_getCursorKindSpelling(k));
                        CgStr rKindSp(clang_getCursorKindSpelling(
                                clang_getCursorKind(refd)));
                        std::clog << "When trying to highlight token "
                                << clang_getTokenExtent(tu, tok) << " "
                                << CgStr(clang_getTokenSpelling(tu, tok))
                                << ":\n"
                                << "  Cursor " << clang_getCursorExtent(cur)
                                << " " << kindSp << " references ";
                        if (selfRef) {
                            std::clog << "itself.\n";
                        } else {
                            std::clog << clang_getCursorExtent(refd)
                                      << " " << rKindSp;
                        }
                        std::clog << "  Recursion depth is "
                                  << recursionDepth << '\n';
                        if (recErr)
                            std::clog << "  Maximum depth exceeded.\n";
                        return TokenAttributes::none;
                    }

                    return getTokenAttributes(
                        tok, refd, tu, recursionDepth + 1);
                }

                case CXCursor_ObjCPropertyDecl:
                    return TokenAttributes::varNonstaticMember; // Sorta right.

                case CXCursor_ObjCIvarDecl:
                case CXCursor_FieldDecl:
                    return TokenAttributes::varNonstaticMember; // TODO

                case CXCursor_EnumConstantDecl:
                case CXCursor_NonTypeTemplateParameter:
                    return TokenAttributes::constant;

                case CXCursor_FunctionDecl:
                case CXCursor_ObjCInstanceMethodDecl:
                case CXCursor_ObjCClassMethodDecl:
                case CXCursor_CXXMethod:
                case CXCursor_FunctionTemplate:
                case CXCursor_Constructor:
                case CXCursor_Destructor:
                case CXCursor_ConversionFunction:
                case CXCursor_OverloadedDeclRef:
                    return TokenAttributes::func;

                case CXCursor_VarDecl:
                    return getVarTokenAttributes(cur);
                case CXCursor_ParmDecl:
                    return TokenAttributes::varLocal;

                case CXCursor_Namespace:
                case CXCursor_NamespaceAlias:
                case CXCursor_UsingDirective:
                case CXCursor_NamespaceRef:
                    return TokenAttributes::namesp;

                case CXCursor_LabelStmt:
                    return TokenAttributes::lbl;

                default:
                    if (clang_isAttribute(k))
                        return TokenAttributes::attr;
                    return TokenAttributes::none;
            }
            SYNTH_DISCLANGWARN_END
            assert("unreachable" && false);
    }
}

static void processToken(FileState& state, CXToken tok, CXCursor cur)
{
    auto& markups = state.hlFile.markups;
    markups.emplace_back();
    Markup& m = markups.back();
    CXTranslationUnit tu = clang_Cursor_getTranslationUnit(cur);
    CXSourceRange rng = clang_getTokenExtent(tu, tok);
    unsigned lineno;
    clang_getFileLocation(
        clang_getRangeStart(rng), nullptr, &lineno, nullptr, &m.beginOffset);
    clang_getFileLocation(
        clang_getRangeEnd(rng), nullptr, nullptr, nullptr, &m.endOffset);
    if (m.beginOffset == m.endOffset) {
        markups.pop_back();
        return;
    }

    m.refd.file = nullptr;
    m.attrs = getTokenAttributes(tok, cur, tu);

    CXTokenKind tk = clang_getTokenKind(tok);
    if (tk == CXToken_Comment || tk == CXToken_Literal)
        return;

    if (!clang_equalLocations(
            clang_getRangeStart(rng), clang_getCursorLocation(cur))
    ) {
        return;
    }

    CXCursorKind k = clang_getCursorKind(cur);
    if (k == CXCursor_InclusionDirective) {
        Markup incLnk = {};
        CXSourceRange incrng = clang_getCursorExtent(cur);
        clang_getFileLocation(
            clang_getRangeStart(incrng),
            nullptr,
            nullptr,
            nullptr,
            &incLnk.beginOffset);
        clang_getFileLocation(
            clang_getRangeEnd(incrng),
            nullptr,
            nullptr,
            nullptr,
            &incLnk.endOffset);
        if (linkInclude(incLnk, cur, state.multiTuProcessor))
            state.hlFile.markups.push_back(std::move(incLnk));
        return;
    }

    if (clang_isDeclaration(k))
        m.attrs |= TokenAttributes::flagDecl;

    // clang_isReference() sometimes reports false negatives, e.g. for
    // overloaded operators, so check manually.
    CXCursor referenced = clang_getCursorReferenced(cur);
    bool isref = !clang_Cursor_isNull(referenced)
        && !clang_equalCursors(cur, referenced);
    if (isref)
        linkCursorIfIncludedDst(m, referenced, lineno, state.multiTuProcessor);

    CXCursor defcur = clang_getCursorDefinition(cur);
    if (clang_equalCursors(defcur, cur)) { // This is a definition:
        m.attrs |= TokenAttributes::flagDef;
        CgStr usr(clang_getCursorUSR(cur));
        if (!usr.empty()) {
            SourceLocation decl {&state.hlFile, lineno};
            state.multiTuProcessor.registerDef(usr.get(), std::move(decl));
        }
    } else if (!isref) {
        if (clang_Cursor_isNull(defcur)) {
            CgStr usr(clang_getCursorUSR(cur));
            if (!usr.empty()) {
                state.multiTuProcessor.registerMissingDefLink(
                    state.hlFile,
                    state.hlFile.markups.size() - 1,
                    usr.get());
            }
        } else {
            linkCursorIfIncludedDst(m, defcur, lineno, state.multiTuProcessor);
        }
    }
}

namespace {

struct IncVisitorData {
    MultiTuProcessor& multiTuProcessor;
    CXTranslationUnit tu;
};

} // anonymous namespace

static void processFile(
    CXFile file, CXSourceLocation*, unsigned, CXClientData ud)
{
    auto& cdata = *static_cast<IncVisitorData*>(ud);
    CXTranslationUnit tu = cdata.tu;
    MultiTuProcessor& multiTuProcessor = cdata.multiTuProcessor;

    CXSourceLocation beg = clang_getLocationForOffset(tu, file, 0);
    CXSourceLocation end = clang_getLocation(tu, file, UINT_MAX, UINT_MAX);

    auto hlFile = multiTuProcessor.prepareToProcess(file);
    if (!hlFile)
        return;

    CXToken* tokens;
    unsigned numTokens;
    clang_tokenize(tu, clang_getRange(beg, end), &tokens, &numTokens);
    CgTokensCleanup tokCleanup(tokens, numTokens, tu);

    if (numTokens > 0) {
        FileState state {*hlFile, multiTuProcessor};
        std::vector<CXCursor> tokCurs(numTokens);
        clang_annotateTokens(tu, tokens, numTokens, tokCurs.data());
        for (unsigned i = 0; i < numTokens - 1; ++i) {
            CXCursor cur = tokCurs[i];
            CXSourceLocation tokLoc = clang_getTokenLocation(tu, tokens[i]);
            if (!clang_equalLocations(clang_getCursorLocation(cur), tokLoc)) {
                CXCursor c2 = clang_getCursor(tu, tokLoc);
                if (clang_equalLocations(clang_getCursorLocation(c2), tokLoc))
                    cur = c2;
            }
            processToken(state, tokens[i], cur);
        }
    }
    std::cout << "Processed " << numTokens << " tokens in "
              << hlFile->inOutDir->first / hlFile->fname << '\n';
}

int synth::processTu(
    CXIndex cidx,
    MultiTuProcessor& state,
    char const* const* args,
    int nargs)
{
    CXTranslationUnit tu = nullptr;
    CXErrorCode err = clang_parseTranslationUnit2FullArgv(
        cidx,
        /*source_filename:*/ nullptr, // Included in commandline.
        args,
        nargs,
        /*unsaved_files:*/ nullptr,
        /*num_unsaved_files:*/ 0,
        CXTranslationUnit_DetailedPreprocessingRecord,
        &tu);
    CgTuHandle htu(tu);
    if (err != CXError_Success) {
        std::cerr << "Failed parsing translation unit (code "
                  << static_cast<int>(err)
                  << ")\n";
        std::cerr << "  args:";
        for (int i = 0; i < nargs; ++i)
            std::cerr << ' ' << args[i];
        std::cerr << '\n';
        return err + 10;
    }

    IncVisitorData ud {state, tu};
    clang_getInclusions(tu, &processFile, &ud);
    return EXIT_SUCCESS;
}
<commit_msg>annotate: Don't warn about self-refs.<commit_after>#include "CgStr.hpp"
#include "output.hpp"
#include "MultiTuProcessor.hpp"
#include "annotate.hpp"
#include "cgWrappers.hpp"
#include "config.hpp"
#include "xref.hpp"
#include "debug.hpp"

#include <climits>
#include <cstring>
#include <iostream>
#include <string>

using namespace synth;

static const unsigned kMaxRefRecursion = 16;

namespace {

struct FileState {
    HighlightedFile& hlFile;
    MultiTuProcessor& multiTuProcessor;
};

} // anonymous namespace

static bool isTypeKind(CXCursorKind k)
{
    SYNTH_DISCLANGWARN_BEGIN("-Wswitch-enum")
    switch (k) {
        case CXCursor_ClassDecl:
        case CXCursor_ClassTemplate:
        case CXCursor_ClassTemplatePartialSpecialization:
        case CXCursor_StructDecl:
        case CXCursor_UnionDecl:
        case CXCursor_EnumDecl:
        case CXCursor_TypedefDecl:
        case CXCursor_ObjCInterfaceDecl:
        case CXCursor_ObjCCategoryDecl:
        case CXCursor_ObjCProtocolDecl:
        case CXCursor_ObjCImplementationDecl:
        case CXCursor_TemplateTypeParameter:
        case CXCursor_TemplateTemplateParameter:
        case CXCursor_TypeAliasDecl:
        case CXCursor_TypeAliasTemplateDecl:
        case CXCursor_TypeRef:
        case CXCursor_ObjCSuperClassRef:
        case CXCursor_ObjCProtocolRef:
        case CXCursor_ObjCClassRef:
        case CXCursor_CXXBaseSpecifier:
            return true;

        default:
            return false;
    }
    SYNTH_DISCLANGWARN_END
}

static TokenAttributes getVarTokenAttributes(CXCursor cur)
{
    if (clang_getCursorLinkage(cur) == CXLinkage_NoLinkage)
        return TokenAttributes::varLocal;
    if (clang_getCXXAccessSpecifier(cur) == CX_CXXInvalidAccessSpecifier)
        return TokenAttributes::varGlobal;
    if (clang_Cursor_getStorageClass(cur) == CX_SC_Static)
        return TokenAttributes::varStaticMember;
    return TokenAttributes::varNonstaticMember;
}

static TokenAttributes getIntCssClasses(CXToken tok, CXTranslationUnit tu)
{
    std::string sp = CgStr(clang_getTokenSpelling(tu, tok)).gets();
    if (!sp.empty()) {
        if (sp.size() >= 2 && sp[0] == '0') {
            if (sp[1] == 'x' || sp[1] == 'X')
                return TokenAttributes::litNumIntHex;
            if (sp[1] == 'b' || sp[1] == 'B')
                return TokenAttributes::litNumIntBin;
            return TokenAttributes::litNumIntOct;
        }
        char suffix = sp[sp.size() - 1];
        if (suffix == 'l' || suffix == 'L')
            return TokenAttributes::litNumIntDecLong;
    }
    return TokenAttributes::litNum;
}

static bool startsWith(std::string const& s, std::string const& p) {
    return s.compare(0, p.size(), p) == 0;
}

static bool isBuiltinTypeKw(std::string const& t) {
    return startsWith(t, "unsigned ")
        || t == "unsigned"
        || startsWith(t, "signed ")
        || t == "signed"
        || startsWith(t, "short ")
        || t == "short"
        || startsWith(t, "long ")
        || t == "long"
        || t == "int"
        || t == "float"
        || t == "double"
        || t == "bool"
        || t == "char"
        || t == "char16_t"
        || t == "char32_t"
        || t == "wchar_t";
}

static TokenAttributes getTokenAttributes(
    CXToken tok, CXCursor cur, CXTranslationUnit tu, unsigned recursionDepth = 0)
{
    CXCursorKind k = clang_getCursorKind(cur);
    CXTokenKind tk = clang_getTokenKind(tok);
    if (clang_isPreprocessing(k)) {
        if (k == CXCursor_InclusionDirective) {
            CgStr spelling = clang_getTokenSpelling(tu, tok);
            if (std::strcmp(spelling.gets(), "include") != 0
                    && std::strcmp(spelling.gets(), "#") != 0
            ) {
                return TokenAttributes::preIncludeFile;
            }
        }
        return TokenAttributes::pre;
    }

    switch (tk) {
        case CXToken_Punctuation:
            if (k == CXCursor_BinaryOperator || k == CXCursor_UnaryOperator)
                return TokenAttributes::op;
            return TokenAttributes::punct;

        case CXToken_Comment:
            return TokenAttributes::cmmt;

        case CXToken_Literal:
            SYNTH_DISCLANGWARN_BEGIN("-Wswitch-enum")
            switch (k) {
                case CXCursor_ObjCStringLiteral:
                case CXCursor_StringLiteral:
                    return TokenAttributes::litStr;
                case CXCursor_CharacterLiteral:
                    return TokenAttributes::litChr;
                case CXCursor_FloatingLiteral:
                    return TokenAttributes::litNumFlt;
                case CXCursor_IntegerLiteral:
                    return getIntCssClasses(tok, tu);
                case CXCursor_ImaginaryLiteral:
                    return TokenAttributes::litNum;
                default:
                    return TokenAttributes::lit;
            }
            SYNTH_DISCLANGWARN_END

        case CXToken_Keyword: {
            if (k == CXCursor_BinaryOperator || k == CXCursor_UnaryOperator)
                return TokenAttributes::opWord;
            if (k == CXCursor_CXXNullPtrLiteralExpr
                || k == CXCursor_CXXBoolLiteralExpr
                || k == CXCursor_ObjCBoolLiteralExpr
            ) {
                return TokenAttributes::litKw;
            }
            std::string sp = CgStr(clang_getTokenSpelling(tu, tok)).gets();
            if (k == CXCursor_TypeRef || isBuiltinTypeKw(sp))
                return TokenAttributes::tyBuiltin;
            if (clang_isDeclaration(k))
                return TokenAttributes::kwDecl;
            return TokenAttributes::kw;
        }

        case CXToken_Identifier:
            if (isTypeKind(k))
                return TokenAttributes::ty;
            SYNTH_DISCLANGWARN_BEGIN("-Wswitch-enum")
            switch (k) {
                case CXCursor_MemberRef:
                case CXCursor_DeclRefExpr:
                case CXCursor_MemberRefExpr:
                case CXCursor_UsingDeclaration:
                case CXCursor_TemplateRef: {
                    CXCursor refd = clang_getCursorReferenced(cur);
                    bool recErr = recursionDepth > kMaxRefRecursion;
                    if (recErr) {
                        CgStr kindSp(clang_getCursorKindSpelling(k));
                        CgStr rKindSp(clang_getCursorKindSpelling(
                                clang_getCursorKind(refd)));
                        std::clog << "When trying to highlight token "
                                << clang_getTokenExtent(tu, tok) << " "
                                << CgStr(clang_getTokenSpelling(tu, tok))
                                << ":\n"
                                << "  Cursor " << clang_getCursorExtent(cur)
                                << " " << kindSp << " references "
                                << clang_getCursorExtent(refd)
                                << " " << rKindSp
                                << "  Maximum depth exceeded with "
                                << recursionDepth << ".\n";
                        return TokenAttributes::none;
                    }

                    if (clang_equalCursors(cur, refd))
                        return TokenAttributes::none;

                    return getTokenAttributes(
                        tok, refd, tu, recursionDepth + 1);
                }

                case CXCursor_ObjCPropertyDecl:
                    return TokenAttributes::varNonstaticMember; // Sorta right.

                case CXCursor_ObjCIvarDecl:
                case CXCursor_FieldDecl:
                    return TokenAttributes::varNonstaticMember; // TODO

                case CXCursor_EnumConstantDecl:
                case CXCursor_NonTypeTemplateParameter:
                    return TokenAttributes::constant;

                case CXCursor_FunctionDecl:
                case CXCursor_ObjCInstanceMethodDecl:
                case CXCursor_ObjCClassMethodDecl:
                case CXCursor_CXXMethod:
                case CXCursor_FunctionTemplate:
                case CXCursor_Constructor:
                case CXCursor_Destructor:
                case CXCursor_ConversionFunction:
                case CXCursor_OverloadedDeclRef:
                    return TokenAttributes::func;

                case CXCursor_VarDecl:
                    return getVarTokenAttributes(cur);
                case CXCursor_ParmDecl:
                    return TokenAttributes::varLocal;

                case CXCursor_Namespace:
                case CXCursor_NamespaceAlias:
                case CXCursor_UsingDirective:
                case CXCursor_NamespaceRef:
                    return TokenAttributes::namesp;

                case CXCursor_LabelStmt:
                    return TokenAttributes::lbl;

                default:
                    if (clang_isAttribute(k))
                        return TokenAttributes::attr;
                    return TokenAttributes::none;
            }
            SYNTH_DISCLANGWARN_END
            assert("unreachable" && false);
    }
}

static void processToken(FileState& state, CXToken tok, CXCursor cur)
{
    auto& markups = state.hlFile.markups;
    markups.emplace_back();
    Markup& m = markups.back();
    CXTranslationUnit tu = clang_Cursor_getTranslationUnit(cur);
    CXSourceRange rng = clang_getTokenExtent(tu, tok);
    unsigned lineno;
    clang_getFileLocation(
        clang_getRangeStart(rng), nullptr, &lineno, nullptr, &m.beginOffset);
    clang_getFileLocation(
        clang_getRangeEnd(rng), nullptr, nullptr, nullptr, &m.endOffset);
    if (m.beginOffset == m.endOffset) {
        markups.pop_back();
        return;
    }

    m.refd.file = nullptr;
    m.attrs = getTokenAttributes(tok, cur, tu);

    CXTokenKind tk = clang_getTokenKind(tok);
    if (tk == CXToken_Comment || tk == CXToken_Literal)
        return;

    if (!clang_equalLocations(
            clang_getRangeStart(rng), clang_getCursorLocation(cur))
    ) {
        return;
    }

    CXCursorKind k = clang_getCursorKind(cur);
    if (k == CXCursor_InclusionDirective) {
        Markup incLnk = {};
        CXSourceRange incrng = clang_getCursorExtent(cur);
        clang_getFileLocation(
            clang_getRangeStart(incrng),
            nullptr,
            nullptr,
            nullptr,
            &incLnk.beginOffset);
        clang_getFileLocation(
            clang_getRangeEnd(incrng),
            nullptr,
            nullptr,
            nullptr,
            &incLnk.endOffset);
        if (linkInclude(incLnk, cur, state.multiTuProcessor))
            state.hlFile.markups.push_back(std::move(incLnk));
        return;
    }

    if (clang_isDeclaration(k))
        m.attrs |= TokenAttributes::flagDecl;

    // clang_isReference() sometimes reports false negatives, e.g. for
    // overloaded operators, so check manually.
    CXCursor referenced = clang_getCursorReferenced(cur);
    bool isref = !clang_Cursor_isNull(referenced)
        && !clang_equalCursors(cur, referenced);
    if (isref)
        linkCursorIfIncludedDst(m, referenced, lineno, state.multiTuProcessor);

    CXCursor defcur = clang_getCursorDefinition(cur);
    if (clang_equalCursors(defcur, cur)) { // This is a definition:
        m.attrs |= TokenAttributes::flagDef;
        CgStr usr(clang_getCursorUSR(cur));
        if (!usr.empty()) {
            SourceLocation decl {&state.hlFile, lineno};
            state.multiTuProcessor.registerDef(usr.get(), std::move(decl));
        }
    } else if (!isref) {
        if (clang_Cursor_isNull(defcur)) {
            CgStr usr(clang_getCursorUSR(cur));
            if (!usr.empty()) {
                state.multiTuProcessor.registerMissingDefLink(
                    state.hlFile,
                    state.hlFile.markups.size() - 1,
                    usr.get());
            }
        } else {
            linkCursorIfIncludedDst(m, defcur, lineno, state.multiTuProcessor);
        }
    }
}

namespace {

struct IncVisitorData {
    MultiTuProcessor& multiTuProcessor;
    CXTranslationUnit tu;
};

} // anonymous namespace

static void processFile(
    CXFile file, CXSourceLocation*, unsigned, CXClientData ud)
{
    auto& cdata = *static_cast<IncVisitorData*>(ud);
    CXTranslationUnit tu = cdata.tu;
    MultiTuProcessor& multiTuProcessor = cdata.multiTuProcessor;

    CXSourceLocation beg = clang_getLocationForOffset(tu, file, 0);
    CXSourceLocation end = clang_getLocation(tu, file, UINT_MAX, UINT_MAX);

    auto hlFile = multiTuProcessor.prepareToProcess(file);
    if (!hlFile)
        return;

    CXToken* tokens;
    unsigned numTokens;
    clang_tokenize(tu, clang_getRange(beg, end), &tokens, &numTokens);
    CgTokensCleanup tokCleanup(tokens, numTokens, tu);

    if (numTokens > 0) {
        FileState state {*hlFile, multiTuProcessor};
        std::vector<CXCursor> tokCurs(numTokens);
        clang_annotateTokens(tu, tokens, numTokens, tokCurs.data());
        for (unsigned i = 0; i < numTokens - 1; ++i) {
            CXCursor cur = tokCurs[i];
            CXSourceLocation tokLoc = clang_getTokenLocation(tu, tokens[i]);
            if (!clang_equalLocations(clang_getCursorLocation(cur), tokLoc)) {
                CXCursor c2 = clang_getCursor(tu, tokLoc);
                if (clang_equalLocations(clang_getCursorLocation(c2), tokLoc))
                    cur = c2;
            }
            processToken(state, tokens[i], cur);
        }
    }
    std::cout << "Processed " << numTokens << " tokens in "
              << hlFile->inOutDir->first / hlFile->fname << '\n';
}

int synth::processTu(
    CXIndex cidx,
    MultiTuProcessor& state,
    char const* const* args,
    int nargs)
{
    CXTranslationUnit tu = nullptr;
    CXErrorCode err = clang_parseTranslationUnit2FullArgv(
        cidx,
        /*source_filename:*/ nullptr, // Included in commandline.
        args,
        nargs,
        /*unsaved_files:*/ nullptr,
        /*num_unsaved_files:*/ 0,
        CXTranslationUnit_DetailedPreprocessingRecord,
        &tu);
    CgTuHandle htu(tu);
    if (err != CXError_Success) {
        std::cerr << "Failed parsing translation unit (code "
                  << static_cast<int>(err)
                  << ")\n";
        std::cerr << "  args:";
        for (int i = 0; i < nargs; ++i)
            std::cerr << ' ' << args[i];
        std::cerr << '\n';
        return err + 10;
    }

    IncVisitorData ud {state, tu};
    clang_getInclusions(tu, &processFile, &ud);
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: printerjob.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2003-03-26 14:24:02 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _PSPRINT_PRINTERJOB_HXX_
#define _PSPRINT_PRINTERJOB_HXX_

#ifndef __SGI_STL_LIST
#include <list>
#endif
#ifndef _PSPRINT_JOBDATA_HXX_
#include <psprint/jobdata.hxx>
#endif
#ifndef _OSL_FILE_HXX_
#include <osl/file.hxx>
#endif
#ifndef _RTL_STRING_HXX_
#include <rtl/string.hxx>
#endif

namespace psp {

// forward declarations
class PrinterGfx;

class PrinterJob
{
private:            // private data

    rtl::OUString           maSpoolDirName;
    rtl::OUString           maFileName; // empty: spool to command, else spool to named file
    int                     mnFileMode;

    osl::File*              mpJobHeader;
    osl::File*              mpJobTrailer;

    std::list< osl::File* > maPageList;
    std::list< osl::File* > maHeaderList;

    JobData                 m_aDocumentJobData;
    JobData                 m_aLastJobData;
    PrinterGfx*             m_pGraphics;

    sal_uInt32      mnResolution;

    sal_uInt32      mnWidthPt;
    sal_uInt32      mnHeightPt;
    sal_uInt32      mnMaxWidthPt;
    sal_uInt32      mnMaxHeightPt;

    sal_uInt32      mnLMarginPt;
    sal_uInt32      mnRMarginPt;
    sal_uInt32      mnTMarginPt;
    sal_uInt32      mnBMarginPt;

    double          mfXScale;
    double          mfYScale;

    sal_Int32       mnErrorCode;

private:            // private methods

    osl::File*      CreateSpoolFile (const rtl::OUString& rName,
                                     const rtl::OUString& rExtension);
    void            InitPaperSize (const JobData& rJobSetup);

    bool            writeFeatureList( osl::File* pFile, const JobData&, bool bDocumentSetup );
    bool            writeSetup( osl::File* pFile, const JobData& );
    bool            writePageSetup( osl::File* pFile, const JobData& );
    bool            writeProlog (osl::File* pFile);

public:             // for usage in PrinterGfx

    sal_uInt32      GetResolution () const { return mnResolution; }
    void            GetScale (double &rXScale, double &rYScale) const;
    sal_uInt16      GetDepth () const;
    sal_uInt16      GetPostscriptLevel (const JobData *pJobData = NULL) const;
    sal_Bool        IsColorPrinter () const;

    osl::File*      GetDocumentHeader ();
    osl::File*      GetDocumentTrailer ();
    osl::File*      GetCurrentPageHeader ();
    osl::File*      GetCurrentPageBody ();

    const ::rtl::OUString& GetPrinterName() const { return m_aLastJobData.m_aPrinterName; }

public:
    PrinterJob ();
    ~PrinterJob ();

    /*  rFileName: if length is greater than 0 save resulting PostScript
     *  to named file.
     *  nMode: only meaningful when saving to file: if nonzero, try
     *  to impose the mode on the resulting file's inode; for nonexistant
     *  files use open, for existant files try a chmod
     *  rJobName: text to appear in the %%Title comment
     *  rAppName: text to appear in the %%Creator comment
     *  rSetupData: JobData that apply to this job
     *  pGraphics: the graphics used to print this job;
     *             this graphics must live until End/AbortJob has returned
     */
    sal_Bool        StartJob (const rtl::OUString& rFileName,
                              int nMode,
                              const rtl::OUString& rJobName,
                              const rtl::OUString& rAppName,
                              const JobData& rSetupData,
                              PrinterGfx* pGraphics
                              );
    sal_Bool        EndJob ();

    sal_Bool        AbortJob ();

    sal_Bool        StartPage (const JobData& rJobSetup, sal_Bool bNewJobData);
    sal_Bool        EndPage ();

    sal_uInt32      GetErrorCode ();
};

}  /* namespace psp */

#endif /* _PSPRINT_PRINTERJOB_HXX_ */

<commit_msg>INTEGRATION: CWS geordi2q14 (1.4.76); FILE MERGED 2004/01/29 18:04:05 hr 1.4.76.1: #111934#: merge CWS ooo111fix2<commit_after>/*************************************************************************
 *
 *  $RCSfile: printerjob.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2004-02-02 18:53:32 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _PSPRINT_PRINTERJOB_HXX_
#define _PSPRINT_PRINTERJOB_HXX_

#ifndef __SGI_STL_LIST
#include <list>
#endif
#ifndef _PSPRINT_JOBDATA_HXX_
#include <psprint/jobdata.hxx>
#endif
#ifndef _OSL_FILE_HXX_
#include <osl/file.hxx>
#endif
#ifndef _RTL_STRING_HXX_
#include <rtl/string.hxx>
#endif

namespace psp {

// forward declarations
class PrinterGfx;

class PrinterJob
{
private:            // private data

    rtl::OUString           maSpoolDirName;
    rtl::OUString           maFileName; // empty: spool to command, else spool to named file
    int                     mnFileMode;
    rtl::OUString           maJobName;

    osl::File*              mpJobHeader;
    osl::File*              mpJobTrailer;

    std::list< osl::File* > maPageList;
    std::list< osl::File* > maHeaderList;

    JobData                 m_aDocumentJobData;
    JobData                 m_aLastJobData;
    PrinterGfx*             m_pGraphics;

    sal_uInt32      mnResolution;

    sal_uInt32      mnWidthPt;
    sal_uInt32      mnHeightPt;
    sal_uInt32      mnMaxWidthPt;
    sal_uInt32      mnMaxHeightPt;

    sal_uInt32      mnLMarginPt;
    sal_uInt32      mnRMarginPt;
    sal_uInt32      mnTMarginPt;
    sal_uInt32      mnBMarginPt;

    double          mfXScale;
    double          mfYScale;

    sal_Int32       mnErrorCode;

private:            // private methods

    osl::File*      CreateSpoolFile (const rtl::OUString& rName,
                                     const rtl::OUString& rExtension);
    void            InitPaperSize (const JobData& rJobSetup);

    bool            writeFeatureList( osl::File* pFile, const JobData&, bool bDocumentSetup );
    bool            writeSetup( osl::File* pFile, const JobData& );
    bool            writePageSetup( osl::File* pFile, const JobData& );
    bool            writeProlog (osl::File* pFile);

public:             // for usage in PrinterGfx

    sal_uInt32      GetResolution () const { return mnResolution; }
    void            GetScale (double &rXScale, double &rYScale) const;
    sal_uInt16      GetDepth () const;
    sal_uInt16      GetPostscriptLevel (const JobData *pJobData = NULL) const;
    sal_Bool        IsColorPrinter () const;

    osl::File*      GetDocumentHeader ();
    osl::File*      GetDocumentTrailer ();
    osl::File*      GetCurrentPageHeader ();
    osl::File*      GetCurrentPageBody ();

    const ::rtl::OUString& GetPrinterName() const { return m_aLastJobData.m_aPrinterName; }

public:
    PrinterJob ();
    ~PrinterJob ();

    /*  rFileName: if length is greater than 0 save resulting PostScript
     *  to named file.
     *  nMode: only meaningful when saving to file: if nonzero, try
     *  to impose the mode on the resulting file's inode; for nonexistant
     *  files use open, for existant files try a chmod
     *  rJobName: text to appear in the %%Title comment
     *  rAppName: text to appear in the %%Creator comment
     *  rSetupData: JobData that apply to this job
     *  pGraphics: the graphics used to print this job;
     *             this graphics must live until End/AbortJob has returned
     */
    sal_Bool        StartJob (const rtl::OUString& rFileName,
                              int nMode,
                              const rtl::OUString& rJobName,
                              const rtl::OUString& rAppName,
                              const JobData& rSetupData,
                              PrinterGfx* pGraphics
                              );
    sal_Bool        EndJob ();

    sal_Bool        AbortJob ();

    sal_Bool        StartPage (const JobData& rJobSetup, sal_Bool bNewJobData);
    sal_Bool        EndPage ();

    sal_uInt32      GetErrorCode ();
};

}  /* namespace psp */

#endif /* _PSPRINT_PRINTERJOB_HXX_ */

<|endoftext|>