<commit_before>/*

Copyright (c) 2003, Magnus Jonsson & Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/file.hpp"
#include "libtorrent/utf8.hpp"

#include <sstream>
#include <windows.h>

namespace
{
	// must be used to not leak memory in case something would throw
	class auto_localfree
	{
	public:
		auto_localfree(HLOCAL memory)
			: m_memory(memory)
		{
		}
		~auto_localfree()
		{
			if (m_memory)
				LocalFree(m_memory);
		}
	private:
		HLOCAL m_memory;
	};

	std::string utf8_native(std::string const& s)
	{
		std::wstring ws;
		libtorrent::utf8_wchar(s, ws);
		std::size_t size = wcstombs(0, ws.c_str(), 0);
		if (size == std::size_t(-1)) return s;
		std::string ret(size + 1);
		size = wcstombs(&ret[0], ws.c_str(), size + 1);
		ret.resize(size - 1);
		return ret;
	}

	void throw_exception(const char* thrower)
	{
		DWORD err = GetLastError();

#ifdef UNICODE
		wchar_t *wbuffer = 0;
		FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM
			|FORMAT_MESSAGE_ALLOCATE_BUFFER
			, 0, err, 0, (LPWSTR)&wbuffer, 0, 0);
		auto_localfree auto_free(wbuffer);
		std::string tmp_utf8;
		libtorrent::wchar_utf8(wbuffer, tmp_utf8);
		char const* buffer = tmp_utf8.c_str();
#else
		char* buffer = 0;
		FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM
			|FORMAT_MESSAGE_ALLOCATE_BUFFER
			, 0, err, 0, (LPSTR)&buffer, 0, 0);
		auto_localfree auto_free(buffer);
#endif

		std::stringstream s;
		s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");

		throw libtorrent::file_error(s.str());
	}
}

namespace libtorrent
{

	struct file::impl : boost::noncopyable
	{
		enum open_flags
		{
			read_flag = 1,
			write_flag = 2
		};

		enum seek_mode
		{
			seek_begin = FILE_BEGIN,
			seek_from_here = FILE_CURRENT,
			seek_end = FILE_END
		};

		impl()
		{
			m_file_handle = INVALID_HANDLE_VALUE;
		}

		void open(const char *file_name, open_flags flags)
		{
			assert(file_name);
			assert(flags & (read_flag | write_flag));

			DWORD access_mask = 0;
			if (flags & read_flag)
				access_mask |= GENERIC_READ;
			if (flags & write_flag)
				access_mask |= GENERIC_WRITE;

			assert(access_mask & (GENERIC_READ | GENERIC_WRITE));

		#ifdef UNICODE
			std::wstring wfile_name(utf8_wchar(file_name));
			HANDLE new_handle = CreateFile(
				(LPCWSTR)wfile_name.c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#else
			HANDLE new_handle = CreateFile(
				utf8_native(file_name).c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#endif

			if (new_handle == INVALID_HANDLE_VALUE)
			{
				std::stringstream s;
				throw_exception(file_name);
			}
			// will only close old file if the open succeeded
			close();
			m_file_handle = new_handle;
		}

		void close()
		{
			if (m_file_handle != INVALID_HANDLE_VALUE)
			{
				CloseHandle(m_file_handle);
				m_file_handle = INVALID_HANDLE_VALUE;
			}
		}

		~impl()
		{
			close();
		}

		size_type write(const char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);
			DWORD bytes_written = 0;
			if (num_bytes != 0)
			{
				if (FALSE == WriteFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_written
					, 0))
				{
					throw_exception("file::write");
				}
			}
			return bytes_written;
		}

		size_type read(char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);

			DWORD bytes_read = 0;
			if (num_bytes != 0)
			{
				if (FALSE == ReadFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_read
					, 0))
				{
					throw_exception("file::read");
				}
			}
			return bytes_read;
		}

		void seek(size_type pos, seek_mode from_where)
		{
			assert(pos >= 0 || from_where != seek_begin);
			assert(pos <= 0 || from_where != seek_end);
			LARGE_INTEGER offs;
			offs.QuadPart = pos;
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, from_where))
			{
				throw_exception("file::seek");
			}
		}

		size_type tell()
		{
			LARGE_INTEGER offs;
			offs.QuadPart = 0;

			// is there any other way to get offset?
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, FILE_CURRENT))
			{
				throw_exception("file::tell");
			}

			size_type pos=offs.QuadPart;
			assert(pos>=0);
			return pos;
		}
/*
		size_type size()
		{
			LARGE_INTEGER s;
			if (FALSE == GetFileSizeEx(m_file_handle, &s))
			{
				throw_exception("file::size");
			}

			size_type size = s.QuadPart;
			assert(size >= 0);
			return size;
		}
*/
	private:

		HANDLE m_file_handle;

	};
}

namespace libtorrent
{

	const file::seek_mode file::begin(file::impl::seek_begin);
	const file::seek_mode file::end(file::impl::seek_end);

	const file::open_mode file::in(file::impl::read_flag);
	const file::open_mode file::out(file::impl::write_flag);

	file::file()
		: m_impl(new libtorrent::file::impl())
	{
	}
	file::file(boost::filesystem::path const& p, open_mode m)
		: m_impl(new libtorrent::file::impl())
	{
		open(p,m);
	}

	file::~file()
	{
	}

	void file::open(boost::filesystem::path const& p, open_mode m)
	{
		assert(p.is_complete());
		m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buffer, size_type num_bytes)
	{
		return m_impl->write(buffer, num_bytes);
	}

	size_type file::read(char* buffer, size_type num_bytes)
	{
		return m_impl->read(buffer, num_bytes);
	}

	void file::seek(size_type pos, seek_mode m)
	{
		m_impl->seek(pos,impl::seek_mode(m.m_val));
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}
}
<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, Magnus Jonsson & Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/file.hpp"
#include "libtorrent/utf8.hpp"

#include <sstream>
#include <windows.h>

namespace
{
	// must be used to not leak memory in case something would throw
	class auto_localfree
	{
	public:
		auto_localfree(HLOCAL memory)
			: m_memory(memory)
		{
		}
		~auto_localfree()
		{
			if (m_memory)
				LocalFree(m_memory);
		}
	private:
		HLOCAL m_memory;
	};

	std::string utf8_native(std::string const& s)
	{
		std::wstring ws;
		libtorrent::utf8_wchar(s, ws);
		std::size_t size = wcstombs(0, ws.c_str(), 0);
		if (size == std::size_t(-1)) return s;
		std::string ret;
		ret.resize(size);
		size = wcstombs(&ret[0], ws.c_str(), size + 1);
		ret.resize(size);
		return ret;
	}

	void throw_exception(const char* thrower)
	{
		DWORD err = GetLastError();

#ifdef UNICODE
		wchar_t *wbuffer = 0;
		FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM
			|FORMAT_MESSAGE_ALLOCATE_BUFFER
			, 0, err, 0, (LPWSTR)&wbuffer, 0, 0);
		auto_localfree auto_free(wbuffer);
		std::string tmp_utf8;
		libtorrent::wchar_utf8(wbuffer, tmp_utf8);
		char const* buffer = tmp_utf8.c_str();
#else
		char* buffer = 0;
		FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM
			|FORMAT_MESSAGE_ALLOCATE_BUFFER
			, 0, err, 0, (LPSTR)&buffer, 0, 0);
		auto_localfree auto_free(buffer);
#endif

		std::stringstream s;
		s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");

		throw libtorrent::file_error(s.str());
	}
}

namespace libtorrent
{

	struct file::impl : boost::noncopyable
	{
		enum open_flags
		{
			read_flag = 1,
			write_flag = 2
		};

		enum seek_mode
		{
			seek_begin = FILE_BEGIN,
			seek_from_here = FILE_CURRENT,
			seek_end = FILE_END
		};

		impl()
		{
			m_file_handle = INVALID_HANDLE_VALUE;
		}

		void open(const char *file_name, open_flags flags)
		{
			assert(file_name);
			assert(flags & (read_flag | write_flag));

			DWORD access_mask = 0;
			if (flags & read_flag)
				access_mask |= GENERIC_READ;
			if (flags & write_flag)
				access_mask |= GENERIC_WRITE;

			assert(access_mask & (GENERIC_READ | GENERIC_WRITE));

		#ifdef UNICODE
			std::wstring wfile_name(utf8_wchar(file_name));
			HANDLE new_handle = CreateFile(
				(LPCWSTR)wfile_name.c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#else
			HANDLE new_handle = CreateFile(
				utf8_native(file_name).c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#endif

			if (new_handle == INVALID_HANDLE_VALUE)
			{
				std::stringstream s;
				throw_exception(file_name);
			}
			// will only close old file if the open succeeded
			close();
			m_file_handle = new_handle;
		}

		void close()
		{
			if (m_file_handle != INVALID_HANDLE_VALUE)
			{
				CloseHandle(m_file_handle);
				m_file_handle = INVALID_HANDLE_VALUE;
			}
		}

		~impl()
		{
			close();
		}

		size_type write(const char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);
			DWORD bytes_written = 0;
			if (num_bytes != 0)
			{
				if (FALSE == WriteFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_written
					, 0))
				{
					throw_exception("file::write");
				}
			}
			return bytes_written;
		}

		size_type read(char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);

			DWORD bytes_read = 0;
			if (num_bytes != 0)
			{
				if (FALSE == ReadFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_read
					, 0))
				{
					throw_exception("file::read");
				}
			}
			return bytes_read;
		}

		void seek(size_type pos, seek_mode from_where)
		{
			assert(pos >= 0 || from_where != seek_begin);
			assert(pos <= 0 || from_where != seek_end);
			LARGE_INTEGER offs;
			offs.QuadPart = pos;
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, from_where))
			{
				throw_exception("file::seek");
			}
		}

		size_type tell()
		{
			LARGE_INTEGER offs;
			offs.QuadPart = 0;

			// is there any other way to get offset?
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, FILE_CURRENT))
			{
				throw_exception("file::tell");
			}

			size_type pos=offs.QuadPart;
			assert(pos>=0);
			return pos;
		}
/*
		size_type size()
		{
			LARGE_INTEGER s;
			if (FALSE == GetFileSizeEx(m_file_handle, &s))
			{
				throw_exception("file::size");
			}

			size_type size = s.QuadPart;
			assert(size >= 0);
			return size;
		}
*/
	private:

		HANDLE m_file_handle;

	};
}

namespace libtorrent
{

	const file::seek_mode file::begin(file::impl::seek_begin);
	const file::seek_mode file::end(file::impl::seek_end);

	const file::open_mode file::in(file::impl::read_flag);
	const file::open_mode file::out(file::impl::write_flag);

	file::file()
		: m_impl(new libtorrent::file::impl())
	{
	}
	file::file(boost::filesystem::path const& p, open_mode m)
		: m_impl(new libtorrent::file::impl())
	{
		open(p,m);
	}

	file::~file()
	{
	}

	void file::open(boost::filesystem::path const& p, open_mode m)
	{
		assert(p.is_complete());
		m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buffer, size_type num_bytes)
	{
		return m_impl->write(buffer, num_bytes);
	}

	size_type file::read(char* buffer, size_type num_bytes)
	{
		return m_impl->read(buffer, num_bytes);
	}

	void file::seek(size_type pos, seek_mode m)
	{
		m_impl->seek(pos,impl::seek_mode(m.m_val));
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Magnus Jonsson & Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/file.hpp"
#include <sstream>

#include <windows.h>

namespace
{
	// must be used to not leak memory in case something would throw
	class auto_LocalFree
	{
	public:
		auto_LocalFree(HLOCAL memory)
			: m_memory(memory)
		{
		}
		~auto_LocalFree()
		{
			if (m_memory)
				LocalFree(m_memory);
		}
	private:
		HLOCAL m_memory;
	};

	void throw_exception(const char* thrower)
	{
		char *buffer = 0;
		int err = GetLastError();

		#ifdef _UNICODE
			FormatMessage(
				FORMAT_MESSAGE_FROM_SYSTEM
				|FORMAT_MESSAGE_ALLOCATE_BUFFER
				, 0, err, 0, (LPWSTR)(LPCSTR)&buffer, 0, 0);
		#else
			FormatMessage(
				FORMAT_MESSAGE_FROM_SYSTEM
				|FORMAT_MESSAGE_ALLOCATE_BUFFER
				, 0, err, 0, (LPSTR)&buffer, 0, 0);
		#endif

		auto_LocalFree auto_free(buffer); // needed for exception safety
		std::stringstream s;
		s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");

		throw libtorrent::file_error(s.str());
	}
}

namespace libtorrent
{

	struct file::impl : boost::noncopyable
	{
		enum open_flags
		{
			read_flag = 1,
			write_flag = 2
		};

		enum seek_mode
		{
			seek_begin = FILE_BEGIN,
			seek_from_here = FILE_CURRENT,
			seek_end = FILE_END
		};

		impl()
		{
			m_file_handle = INVALID_HANDLE_VALUE;
		}

		void open(const char *file_name, open_flags flags)
		{
			assert(file_name);
			assert(flags & (read_flag | write_flag));

			DWORD access_mask = 0;
			if (flags & read_flag)
				access_mask |= GENERIC_READ;
			if (flags & write_flag)
				access_mask |= GENERIC_WRITE;

			assert(access_mask & (GENERIC_READ | GENERIC_WRITE));

		#ifdef _UNICODE
			std::wstring wfile_name(utf8_wchar(file_name));
			HANDLE new_handle = CreateFile(
				(LPCWSTR)wfile_name.c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#else
			HANDLE new_handle = CreateFile(
				file_name
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#endif

			if (new_handle == INVALID_HANDLE_VALUE)
			{
				std::stringstream s;
				throw_exception(file_name);
			}
			// will only close old file if the open succeeded
			close();
			m_file_handle = new_handle;
		}

		void close()
		{
			if (m_file_handle != INVALID_HANDLE_VALUE)
			{
				CloseHandle(m_file_handle);
				m_file_handle = INVALID_HANDLE_VALUE;
			}
		}

		~impl()
		{
			close();
		}

		size_type write(const char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);
			DWORD bytes_written = 0;
			if (num_bytes != 0)
			{
				if (FALSE == WriteFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_written
					, 0))
				{
					throw_exception("file::write");
				}
			}
			return bytes_written;
		}

		size_type read(char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);

			DWORD bytes_read = 0;
			if (num_bytes != 0)
			{
				if (FALSE == ReadFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_read
					, 0))
				{
					throw_exception("file::read");
				}
			}
			return bytes_read;
		}

		void seek(size_type pos, seek_mode from_where)
		{
			assert(pos >= 0 || from_where != seek_begin);
			assert(pos <= 0 || from_where != seek_end);
			LARGE_INTEGER offs;
			offs.QuadPart = pos;
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, from_where))
			{
				throw_exception("file::seek");
			}
		}

		size_type tell()
		{
			LARGE_INTEGER offs;
			offs.QuadPart = 0;

			// is there any other way to get offset?
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, FILE_CURRENT))
			{
				throw_exception("file::tell");
			}

			size_type pos=offs.QuadPart;
			assert(pos>=0);
			return pos;
		}
/*
		size_type size()
		{
			LARGE_INTEGER s;
			if (FALSE == GetFileSizeEx(m_file_handle, &s))
			{
				throw_exception("file::size");
			}

			size_type size = s.QuadPart;
			assert(size >= 0);
			return size;
		}
*/
	private:

		HANDLE m_file_handle;

	};
}

namespace libtorrent
{

	const file::seek_mode file::begin(file::impl::seek_begin);
	const file::seek_mode file::end(file::impl::seek_end);

	const file::open_mode file::in(file::impl::read_flag);
	const file::open_mode file::out(file::impl::write_flag);

	file::file()
		: m_impl(new libtorrent::file::impl())
	{
	}
	file::file(boost::filesystem::path const& p, open_mode m)
		: m_impl(new libtorrent::file::impl())
	{
		open(p,m);
	}

	file::~file()
	{
	}

	void file::open(boost::filesystem::path const& p, open_mode m)
	{
		assert(p.is_complete());
		m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buffer, size_type num_bytes)
	{
		return m_impl->write(buffer, num_bytes);
	}

	size_type file::read(char* buffer, size_type num_bytes)
	{
		return m_impl->read(buffer, num_bytes);
	}

	void file::seek(size_type pos, seek_mode m)
	{
		m_impl->seek(pos,impl::seek_mode(m.m_val));
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}
}
<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, Magnus Jonsson & Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/file.hpp"
#include "libtorrent/utf8.hpp"

#include <sstream>
#include <windows.h>

namespace
{
	// must be used to not leak memory in case something would throw
	class auto_localfree
	{
	public:
		auto_localfree(HLOCAL memory)
			: m_memory(memory)
		{
		}
		~auto_localfree()
		{
			if (m_memory)
				LocalFree(m_memory);
		}
	private:
		HLOCAL m_memory;
	};

	void throw_exception(const char* thrower)
	{
		char *buffer = 0;
		int err = GetLastError();

		#ifdef _UNICODE
			FormatMessage(
				FORMAT_MESSAGE_FROM_SYSTEM
				|FORMAT_MESSAGE_ALLOCATE_BUFFER
				, 0, err, 0, (LPWSTR)(LPCSTR)&buffer, 0, 0);
		#else
			FormatMessage(
				FORMAT_MESSAGE_FROM_SYSTEM
				|FORMAT_MESSAGE_ALLOCATE_BUFFER
				, 0, err, 0, (LPSTR)&buffer, 0, 0);
		#endif

		auto_localfree auto_free(buffer); // needed for exception safety
		std::stringstream s;
		s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");

		throw libtorrent::file_error(s.str());
	}
}

namespace libtorrent
{

	struct file::impl : boost::noncopyable
	{
		enum open_flags
		{
			read_flag = 1,
			write_flag = 2
		};

		enum seek_mode
		{
			seek_begin = FILE_BEGIN,
			seek_from_here = FILE_CURRENT,
			seek_end = FILE_END
		};

		impl()
		{
			m_file_handle = INVALID_HANDLE_VALUE;
		}

		void open(const char *file_name, open_flags flags)
		{
			assert(file_name);
			assert(flags & (read_flag | write_flag));

			DWORD access_mask = 0;
			if (flags & read_flag)
				access_mask |= GENERIC_READ;
			if (flags & write_flag)
				access_mask |= GENERIC_WRITE;

			assert(access_mask & (GENERIC_READ | GENERIC_WRITE));

		#ifdef _UNICODE
			std::wstring wfile_name(utf8_wchar(file_name));
			HANDLE new_handle = CreateFile(
				(LPCWSTR)wfile_name.c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#else
			HANDLE new_handle = CreateFile(
				file_name
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#endif

			if (new_handle == INVALID_HANDLE_VALUE)
			{
				std::stringstream s;
				throw_exception(file_name);
			}
			// will only close old file if the open succeeded
			close();
			m_file_handle = new_handle;
		}

		void close()
		{
			if (m_file_handle != INVALID_HANDLE_VALUE)
			{
				CloseHandle(m_file_handle);
				m_file_handle = INVALID_HANDLE_VALUE;
			}
		}

		~impl()
		{
			close();
		}

		size_type write(const char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);
			DWORD bytes_written = 0;
			if (num_bytes != 0)
			{
				if (FALSE == WriteFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_written
					, 0))
				{
					throw_exception("file::write");
				}
			}
			return bytes_written;
		}

		size_type read(char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);

			DWORD bytes_read = 0;
			if (num_bytes != 0)
			{
				if (FALSE == ReadFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_read
					, 0))
				{
					throw_exception("file::read");
				}
			}
			return bytes_read;
		}

		void seek(size_type pos, seek_mode from_where)
		{
			assert(pos >= 0 || from_where != seek_begin);
			assert(pos <= 0 || from_where != seek_end);
			LARGE_INTEGER offs;
			offs.QuadPart = pos;
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, from_where))
			{
				throw_exception("file::seek");
			}
		}

		size_type tell()
		{
			LARGE_INTEGER offs;
			offs.QuadPart = 0;

			// is there any other way to get offset?
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, FILE_CURRENT))
			{
				throw_exception("file::tell");
			}

			size_type pos=offs.QuadPart;
			assert(pos>=0);
			return pos;
		}
/*
		size_type size()
		{
			LARGE_INTEGER s;
			if (FALSE == GetFileSizeEx(m_file_handle, &s))
			{
				throw_exception("file::size");
			}

			size_type size = s.QuadPart;
			assert(size >= 0);
			return size;
		}
*/
	private:

		HANDLE m_file_handle;

	};
}

namespace libtorrent
{

	const file::seek_mode file::begin(file::impl::seek_begin);
	const file::seek_mode file::end(file::impl::seek_end);

	const file::open_mode file::in(file::impl::read_flag);
	const file::open_mode file::out(file::impl::write_flag);

	file::file()
		: m_impl(new libtorrent::file::impl())
	{
	}
	file::file(boost::filesystem::path const& p, open_mode m)
		: m_impl(new libtorrent::file::impl())
	{
		open(p,m);
	}

	file::~file()
	{
	}

	void file::open(boost::filesystem::path const& p, open_mode m)
	{
		assert(p.is_complete());
		m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buffer, size_type num_bytes)
	{
		return m_impl->write(buffer, num_bytes);
	}

	size_type file::read(char* buffer, size_type num_bytes)
	{
		return m_impl->read(buffer, num_bytes);
	}

	void file::seek(size_type pos, seek_mode m)
	{
		m_impl->seek(pos,impl::seek_mode(m.m_val));
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2010-2017 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
 */

#include <bx/file.h>
#include <bx/os.h>
#include <bx/readerwriter.h>

#if BX_PLATFORM_WINDOWS
extern "C" __declspec(dllimport) uint32_t __stdcall GetTempPathA(uint32_t _max, const char* _ptr);
#endif // BX_PLATFORM_WINDOWS

namespace bx
{
	static bool isPathSeparator(char _ch)
	{
		return false
			|| '/'  == _ch
			|| '\\' == _ch
			;
	}

	static int32_t normalizeFilePath(char* _dst, int32_t _dstSize, const char* _src, int32_t _num)
	{
		// Reference: Lexical File Names in Plan 9 or Getting Dot-Dot Right
		// https://9p.io/sys/doc/lexnames.html

		const int32_t num = strLen(_src, _num);

		if (0 == num)
		{
			return strCopy(_dst, _dstSize, ".");
		}

		int32_t size = 0;

		StaticMemoryBlockWriter writer(_dst, _dstSize);
		Error err;

		int32_t idx      = 0;
		int32_t dotdot   = 0;

		if (2 <= num
		&&  ':' == _src[1])
		{
			size += write(&writer, toUpper(_src[idx]), &err);
			size += write(&writer, ':', &err);
			idx  += 2;
			dotdot = size;
		}

		const int32_t slashIdx = idx;

		bool rooted = isPathSeparator(_src[idx]);
		if (rooted)
		{
			size += write(&writer, '/', &err);
			++idx;
			dotdot = size;
		}

		while (idx < num && err.isOk() )
		{
			switch (_src[idx])
			{
			case '/':
			case '\\':
				++idx;
				break;

			case '.':
				if (idx+1 == num
				||  isPathSeparator(_src[idx+1]) )
				{
					++idx;
					break;
				}

				if ('.' == _src[idx+1]
				&& (idx+2 == num || isPathSeparator(_src[idx+2]) ) )
				{
					idx += 2;

					if (dotdot < size)
					{
						for (--size
							; dotdot < size && !isPathSeparator(_dst[size])
							; --size)
						{
						}
						seek(&writer, size, Whence::Begin);
					}
					else if (!rooted)
					{
						if (0 < size)
						{
							size += write(&writer, '/', &err);
						}

						size += write(&writer, "..", &err);
						dotdot = size;
					}

					break;
				}

				BX_FALLTHROUGH;

			default:
				if ( ( rooted && slashIdx+1 != size)
				||   (!rooted &&          0 != size) )
				{
					size += write(&writer, '/', &err);
				}

				for (; idx < num && !isPathSeparator(_src[idx]); ++idx)
				{
					size += write(&writer, _src[idx], &err);
				}

				break;
			}
		}

		if (0 == size)
		{
			size += write(&writer, '.', &err);
		}

		write(&writer, '\0', &err);

		return size;
	}

	static bool getTempPath(char* _out, uint32_t* _inOutSize)
	{
#if BX_PLATFORM_WINDOWS
		uint32_t len = ::GetTempPathA(*_inOutSize, _out);
		bool result = len != 0 && len < *_inOutSize;
		*_inOutSize = len;
		return result;
#else
		static const char* s_tmp[] =
		{
			"TMPDIR",
			"TMP",
			"TEMP",
			"TEMPDIR",

			NULL
		};

		for (const char** tmp = s_tmp; *tmp != NULL; ++tmp)
		{
			uint32_t len = *_inOutSize;
			*_out = '\0';
			bool result = getenv(*tmp, _out, &len);

			if (result
			&&  len != 0
			&&  len < *_inOutSize)
			{
				*_inOutSize = len;
				return result;
			}
		}

		FileInfo fi;
		if (stat("/tmp", fi)
		&&  FileInfo::Directory == fi.m_type)
		{
			strCopy(_out, *_inOutSize, "/tmp");
			*_inOutSize = 4;
			return true;
		}

		return false;
#endif // BX_PLATFORM_*
	}

	FilePath::FilePath()
	{
		set("");
	}

	FilePath::FilePath(TempDir::Enum)
	{
		set(TempDir::Tag);
	}

	FilePath::FilePath(const char* _rhs)
	{
		set(_rhs);
	}

	FilePath::FilePath(const StringView& _filePath)
	{
		set(_filePath);
	}

	FilePath& FilePath::operator=(const StringView& _rhs)
	{
		set(_rhs);
		return *this;
	}

	void FilePath::set(TempDir::Enum)
	{
		char tmp[kMaxFilePath];
		uint32_t len = BX_COUNTOF(tmp);
		getTempPath(tmp, &len);
		set(StringView(tmp, len) );
	}

	void FilePath::set(const StringView& _filePath)
	{
		normalizeFilePath(
			  m_filePath
			, BX_COUNTOF(m_filePath)
			, _filePath.getPtr()
			, _filePath.getLength()
			);
	}

	void FilePath::join(const StringView& _str)
	{
		char tmp[kMaxFilePath];
		strCopy(tmp, BX_COUNTOF(tmp), m_filePath);
		strCat(tmp, BX_COUNTOF(tmp), "/");
		strCat(tmp, BX_COUNTOF(tmp), _str);
		set(tmp);
	}

	const char* FilePath::get() const
	{
		return m_filePath;
	}

	const StringView FilePath::getPath() const
	{
		const char* end = strRFind(m_filePath, '/');
		if (NULL != end)
		{
			return StringView(m_filePath, end+1);
		}

		return StringView();
	}

	const StringView FilePath::getFileName() const
	{
		const char* fileName = strRFind(m_filePath, '/');
		if (NULL != fileName)
		{
			return StringView(fileName+1);
		}

		return get();
	}

	const StringView FilePath::getBaseName() const
	{
		const StringView fileName = getFileName();
		if (!fileName.isEmpty() )
		{
			const char* ext = strFind(fileName.getPtr(), '.', fileName.getLength() );
			if (ext != NULL)
			{
				return StringView(fileName.getPtr(), ext);
			}
		}

		return StringView();
	}

	const StringView FilePath::getExt() const
	{
		const StringView fileName = getFileName();
		if (!fileName.isEmpty() )
		{
			const char* ext = strFind(fileName.getPtr(), '.', fileName.getLength() );
			return StringView(ext);
		}

		return StringView();
	}

	bool FilePath::isAbsolute() const
	{
		return  '/' == m_filePath[0] // no drive letter
			|| (':' == m_filePath[1] && '/' == m_filePath[2]) // with drive letter
			;
	}

} // namespace bx
<commit_msg>Cleanup.<commit_after>/*
 * Copyright 2010-2017 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
 */

#include <bx/file.h>
#include <bx/os.h>
#include <bx/readerwriter.h>

#if BX_PLATFORM_WINDOWS
extern "C" __declspec(dllimport) uint32_t __stdcall GetTempPathA(uint32_t _max, char* _ptr);
#endif // BX_PLATFORM_WINDOWS

namespace bx
{
	static bool isPathSeparator(char _ch)
	{
		return false
			|| '/'  == _ch
			|| '\\' == _ch
			;
	}

	static int32_t normalizeFilePath(char* _dst, int32_t _dstSize, const char* _src, int32_t _num)
	{
		// Reference: Lexical File Names in Plan 9 or Getting Dot-Dot Right
		// https://9p.io/sys/doc/lexnames.html

		const int32_t num = strLen(_src, _num);

		if (0 == num)
		{
			return strCopy(_dst, _dstSize, ".");
		}

		int32_t size = 0;

		StaticMemoryBlockWriter writer(_dst, _dstSize);
		Error err;

		int32_t idx      = 0;
		int32_t dotdot   = 0;

		if (2 <= num
		&&  ':' == _src[1])
		{
			size += write(&writer, toUpper(_src[idx]), &err);
			size += write(&writer, ':', &err);
			idx  += 2;
			dotdot = size;
		}

		const int32_t slashIdx = idx;

		bool rooted = isPathSeparator(_src[idx]);
		if (rooted)
		{
			size += write(&writer, '/', &err);
			++idx;
			dotdot = size;
		}

		while (idx < num && err.isOk() )
		{
			switch (_src[idx])
			{
			case '/':
			case '\\':
				++idx;
				break;

			case '.':
				if (idx+1 == num
				||  isPathSeparator(_src[idx+1]) )
				{
					++idx;
					break;
				}

				if ('.' == _src[idx+1]
				&& (idx+2 == num || isPathSeparator(_src[idx+2]) ) )
				{
					idx += 2;

					if (dotdot < size)
					{
						for (--size
							; dotdot < size && !isPathSeparator(_dst[size])
							; --size)
						{
						}
						seek(&writer, size, Whence::Begin);
					}
					else if (!rooted)
					{
						if (0 < size)
						{
							size += write(&writer, '/', &err);
						}

						size += write(&writer, "..", &err);
						dotdot = size;
					}

					break;
				}

				BX_FALLTHROUGH;

			default:
				if ( ( rooted && slashIdx+1 != size)
				||   (!rooted &&          0 != size) )
				{
					size += write(&writer, '/', &err);
				}

				for (; idx < num && !isPathSeparator(_src[idx]); ++idx)
				{
					size += write(&writer, _src[idx], &err);
				}

				break;
			}
		}

		if (0 == size)
		{
			size += write(&writer, '.', &err);
		}

		write(&writer, '\0', &err);

		return size;
	}

	static bool getTempPath(char* _out, uint32_t* _inOutSize)
	{
#if BX_PLATFORM_WINDOWS
		uint32_t len = ::GetTempPathA(*_inOutSize, _out);
		bool result = len != 0 && len < *_inOutSize;
		*_inOutSize = len;
		return result;
#else
		static const char* s_tmp[] =
		{
			"TMPDIR",
			"TMP",
			"TEMP",
			"TEMPDIR",

			NULL
		};

		for (const char** tmp = s_tmp; *tmp != NULL; ++tmp)
		{
			uint32_t len = *_inOutSize;
			*_out = '\0';
			bool result = getenv(*tmp, _out, &len);

			if (result
			&&  len != 0
			&&  len < *_inOutSize)
			{
				*_inOutSize = len;
				return result;
			}
		}

		FileInfo fi;
		if (stat("/tmp", fi)
		&&  FileInfo::Directory == fi.m_type)
		{
			strCopy(_out, *_inOutSize, "/tmp");
			*_inOutSize = 4;
			return true;
		}

		return false;
#endif // BX_PLATFORM_*
	}

	FilePath::FilePath()
	{
		set("");
	}

	FilePath::FilePath(TempDir::Enum)
	{
		set(TempDir::Tag);
	}

	FilePath::FilePath(const char* _rhs)
	{
		set(_rhs);
	}

	FilePath::FilePath(const StringView& _filePath)
	{
		set(_filePath);
	}

	FilePath& FilePath::operator=(const StringView& _rhs)
	{
		set(_rhs);
		return *this;
	}

	void FilePath::set(TempDir::Enum)
	{
		char tmp[kMaxFilePath];
		uint32_t len = BX_COUNTOF(tmp);
		getTempPath(tmp, &len);
		set(StringView(tmp, len) );
	}

	void FilePath::set(const StringView& _filePath)
	{
		normalizeFilePath(
			  m_filePath
			, BX_COUNTOF(m_filePath)
			, _filePath.getPtr()
			, _filePath.getLength()
			);
	}

	void FilePath::join(const StringView& _str)
	{
		char tmp[kMaxFilePath];
		strCopy(tmp, BX_COUNTOF(tmp), m_filePath);
		strCat(tmp, BX_COUNTOF(tmp), "/");
		strCat(tmp, BX_COUNTOF(tmp), _str);
		set(tmp);
	}

	const char* FilePath::get() const
	{
		return m_filePath;
	}

	const StringView FilePath::getPath() const
	{
		const char* end = strRFind(m_filePath, '/');
		if (NULL != end)
		{
			return StringView(m_filePath, end+1);
		}

		return StringView();
	}

	const StringView FilePath::getFileName() const
	{
		const char* fileName = strRFind(m_filePath, '/');
		if (NULL != fileName)
		{
			return StringView(fileName+1);
		}

		return get();
	}

	const StringView FilePath::getBaseName() const
	{
		const StringView fileName = getFileName();
		if (!fileName.isEmpty() )
		{
			const char* ext = strFind(fileName.getPtr(), '.', fileName.getLength() );
			if (ext != NULL)
			{
				return StringView(fileName.getPtr(), ext);
			}
		}

		return StringView();
	}

	const StringView FilePath::getExt() const
	{
		const StringView fileName = getFileName();
		if (!fileName.isEmpty() )
		{
			const char* ext = strFind(fileName.getPtr(), '.', fileName.getLength() );
			return StringView(ext);
		}

		return StringView();
	}

	bool FilePath::isAbsolute() const
	{
		return  '/' == m_filePath[0] // no drive letter
			|| (':' == m_filePath[1] && '/' == m_filePath[2]) // with drive letter
			;
	}

} // namespace bx
<|endoftext|>


<commit_before>#include <Source/Headers.h>
#include <Source/TextPos.h>

#include "TextDoc.h"

// ----------------------------------------------------------------------------
TextDoc::TextDoc()
{
}

// ----------------------------------------------------------------------------
TextDoc::TextDoc(const char* ch)
: Lines(1)
{
  Lines[0] = ch;
}

// ----------------------------------------------------------------------------
TextDoc::TextDoc(size_t cLines)
: Lines(cLines)
{
}

// ----------------------------------------------------------------------------
size_t TextDoc::getLineCount() const
{
  return Lines.size();
}

// ----------------------------------------------------------------------------
size_t TextDoc::getLineLength(size_t idx) const
{
  return idx < Lines.size() ? Lines[idx].length() : 0;
}

// ----------------------------------------------------------------------------
size_t TextDoc::getMaxLineLength() const
{
  size_t cLines = Lines.size();
  size_t MaxLineLength = 0;
  for (size_t i = 0; i < cLines; i++) {
    MaxLineLength = std::max(MaxLineLength, Lines[i].length());
  }

  return MaxLineLength;
}

// ----------------------------------------------------------------------------
TextPos TextDoc::getEndOfDoc() const
{
  size_t lastLine = getLineCount()-1;
  return TextPos(lastLine, getLineLength(lastLine));
}

// ----------------------------------------------------------------------------
TextPos TextDoc::getNextPos(const TextPos& Pos) const
{
  TextPos pos(Pos);

  if (++pos.column > getLineLength(pos.line)) {
    ++pos.line;
    pos.column = 0;
  }

  return pos;
}

// ----------------------------------------------------------------------------
TextPos TextDoc::getPrevPos(const TextPos& Pos) const
{
  TextPos pos(Pos);
  if (--pos.column >= getLineLength(pos.line)) {
    --pos.line;
    pos.column = getLineLength(pos.line);
  }

  return pos;
}

// ----------------------------------------------------------------------------
char TextDoc::getCharAt(const TextPos& pos) const
{
  if (pos.line < getLineCount())
  {
    std::string line = getLineAt(pos.line);

    if (pos.column < getLineLength(pos.line)) {
      return line[pos.column];
    } else if (pos.column == getLineLength(pos.line)) {
      return '\n';
    }
  }

  return '\0';
}

// ----------------------------------------------------------------------------
const std::string& TextDoc::getLineAt(size_t idx) const
{
  return Lines.at(idx);
}

// ----------------------------------------------------------------------------
std::string TextDoc::exportContent() const
{
  std::string text;

  size_t cLines = getLineCount();

  for (size_t i = 0; i < cLines; i++)
  {
    const std::string& line = getLineAt(i);

    if (i > 0) {
      text.push_back('\n');
    }

    text.append(line);
  }

  return text;
}

// ----------------------------------------------------------------------------
TextDoc TextDoc::getContent(const TextPos& p0, const TextPos& p1) const
{
  TextDoc doc;

  for (size_t i = p0.line; i <= p1.line; i++)
  {
    std::string line = Lines.at(i);

    if (i == p0.line && i == p1.line) {
      line = line.substr(p0.column, p1.column - p0.column);
    } else if (i == p0.line) {
      line = line.substr(p0.column, std::string::npos);
    } else if (i == p1.line) {
      line = line.substr(0, p1.column);
    }

    doc.Lines.push_back(line);
  }

  return doc;
}

// ----------------------------------------------------------------------------
EditableTextDoc::EditableTextDoc()
: Version(0)
{
}

// ----------------------------------------------------------------------------
void EditableTextDoc::replaceContent(char* pDoc, size_t Length)
{
  if (pDoc == nullptr) {
    return;
  }

  std::vector<char*> lines;
  int SearchMode = 0;

  for (size_t i = 0; i <= Length; i++)
  {
    if (SearchMode == 0) {
      lines.push_back(pDoc+i);
    }

    if (pDoc[i] == '\n') {
      SearchMode = 0;
    } else {
      SearchMode = 1;
    }

    if (pDoc[i] == '\n' || pDoc[i] == '\r') {
      pDoc[i] = '\0';
    }
  }

  Lines.clear();
  Lines.resize(lines.size());

  size_t idx = 0;
  for (auto line : lines) {
    Lines[idx++] = line;
  }

  Version = 0;
}

// ----------------------------------------------------------------------------
void EditableTextDoc::deleteContent(const TextPos& p0, const TextPos& p1)
{
  EditableTextDoc doc;

  size_t cLines = getLineCount();

  doc.Lines.reserve(cLines);

  for (size_t i = 0; i < cLines; i++)
  {
    if (i < p0.line || i > p1.line) {
      doc.Lines.push_back(Lines[i]);
      continue;
    }

    if (i > p0.line && i <= p1.line) {
      continue;
    }

    std::string line0 = Lines[p0.line].substr(0, p0.column);
    std::string line1 = Lines[p1.line].substr(p1.column, std::string::npos);

    doc.Lines.push_back(line0 + line1);
  }

  Lines.swap(doc.Lines);
  Version++;
}

// ----------------------------------------------------------------------------
void EditableTextDoc::insertContent(const TextPos& p, const TextDoc& Content)
{
  if (Content.getLineCount() == 1) {
    Lines.at(p.line).insert(p.column, Content.Lines[0]);
    return;
  }

  std::string l1 = Lines.at(p.line).substr(p.column);

  Lines[p.line].erase(p.column);
  Lines[p.line].append(Content.Lines[0]);

  std::vector<std::string>::iterator it = Lines.insert(Lines.begin() + p.line + 1, Content.Lines.begin() + 1, Content.Lines.end());
  (it + Content.Lines.size() - 2)->append(l1);

  Version++;
}
<commit_msg>Fixed rendering update for single line changes<commit_after>#include <Source/Headers.h>
#include <Source/TextPos.h>

#include "TextDoc.h"

// ----------------------------------------------------------------------------
TextDoc::TextDoc()
{
}

// ----------------------------------------------------------------------------
TextDoc::TextDoc(const char* ch)
: Lines(1)
{
  Lines[0] = ch;
}

// ----------------------------------------------------------------------------
TextDoc::TextDoc(size_t cLines)
: Lines(cLines)
{
}

// ----------------------------------------------------------------------------
size_t TextDoc::getLineCount() const
{
  return Lines.size();
}

// ----------------------------------------------------------------------------
size_t TextDoc::getLineLength(size_t idx) const
{
  return idx < Lines.size() ? Lines[idx].length() : 0;
}

// ----------------------------------------------------------------------------
size_t TextDoc::getMaxLineLength() const
{
  size_t cLines = Lines.size();
  size_t MaxLineLength = 0;
  for (size_t i = 0; i < cLines; i++) {
    MaxLineLength = std::max(MaxLineLength, Lines[i].length());
  }

  return MaxLineLength;
}

// ----------------------------------------------------------------------------
TextPos TextDoc::getEndOfDoc() const
{
  size_t lastLine = getLineCount()-1;
  return TextPos(lastLine, getLineLength(lastLine));
}

// ----------------------------------------------------------------------------
TextPos TextDoc::getNextPos(const TextPos& Pos) const
{
  TextPos pos(Pos);

  if (++pos.column > getLineLength(pos.line)) {
    ++pos.line;
    pos.column = 0;
  }

  return pos;
}

// ----------------------------------------------------------------------------
TextPos TextDoc::getPrevPos(const TextPos& Pos) const
{
  TextPos pos(Pos);
  if (--pos.column >= getLineLength(pos.line)) {
    --pos.line;
    pos.column = getLineLength(pos.line);
  }

  return pos;
}

// ----------------------------------------------------------------------------
char TextDoc::getCharAt(const TextPos& pos) const
{
  if (pos.line < getLineCount())
  {
    std::string line = getLineAt(pos.line);

    if (pos.column < getLineLength(pos.line)) {
      return line[pos.column];
    } else if (pos.column == getLineLength(pos.line)) {
      return '\n';
    }
  }

  return '\0';
}

// ----------------------------------------------------------------------------
const std::string& TextDoc::getLineAt(size_t idx) const
{
  return Lines.at(idx);
}

// ----------------------------------------------------------------------------
std::string TextDoc::exportContent() const
{
  std::string text;

  size_t cLines = getLineCount();

  for (size_t i = 0; i < cLines; i++)
  {
    const std::string& line = getLineAt(i);

    if (i > 0) {
      text.push_back('\n');
    }

    text.append(line);
  }

  return text;
}

// ----------------------------------------------------------------------------
TextDoc TextDoc::getContent(const TextPos& p0, const TextPos& p1) const
{
  TextDoc doc;

  for (size_t i = p0.line; i <= p1.line; i++)
  {
    std::string line = Lines.at(i);

    if (i == p0.line && i == p1.line) {
      line = line.substr(p0.column, p1.column - p0.column);
    } else if (i == p0.line) {
      line = line.substr(p0.column, std::string::npos);
    } else if (i == p1.line) {
      line = line.substr(0, p1.column);
    }

    doc.Lines.push_back(line);
  }

  return doc;
}

// ----------------------------------------------------------------------------
EditableTextDoc::EditableTextDoc()
: Version(0)
{
}

// ----------------------------------------------------------------------------
void EditableTextDoc::replaceContent(char* pDoc, size_t Length)
{
  if (pDoc == nullptr) {
    return;
  }

  std::vector<char*> lines;
  int SearchMode = 0;

  for (size_t i = 0; i <= Length; i++)
  {
    if (SearchMode == 0) {
      lines.push_back(pDoc+i);
    }

    if (pDoc[i] == '\n') {
      SearchMode = 0;
    } else {
      SearchMode = 1;
    }

    if (pDoc[i] == '\n' || pDoc[i] == '\r') {
      pDoc[i] = '\0';
    }
  }

  Lines.clear();
  Lines.resize(lines.size());

  size_t idx = 0;
  for (auto line : lines) {
    Lines[idx++] = line;
  }

  Version = 0;
}

// ----------------------------------------------------------------------------
void EditableTextDoc::deleteContent(const TextPos& p0, const TextPos& p1)
{
  EditableTextDoc doc;

  size_t cLines = getLineCount();

  doc.Lines.reserve(cLines);

  for (size_t i = 0; i < cLines; i++)
  {
    if (i < p0.line || i > p1.line) {
      doc.Lines.push_back(Lines[i]);
      continue;
    }

    if (i > p0.line && i <= p1.line) {
      continue;
    }

    std::string line0 = Lines[p0.line].substr(0, p0.column);
    std::string line1 = Lines[p1.line].substr(p1.column, std::string::npos);

    doc.Lines.push_back(line0 + line1);
  }

  Lines.swap(doc.Lines);
  Version++;
}

// ----------------------------------------------------------------------------
void EditableTextDoc::insertContent(const TextPos& p, const TextDoc& Content)
{
  if (Content.getLineCount() == 1) {
    Lines.at(p.line).insert(p.column, Content.Lines[0]);
  }
  else
  {
    std::string l1 = Lines.at(p.line).substr(p.column);

    Lines[p.line].erase(p.column);
    Lines[p.line].append(Content.Lines[0]);

    std::vector<std::string>::iterator it = Lines.insert(Lines.begin() + p.line + 1, Content.Lines.begin() + 1, Content.Lines.end());
    (it + Content.Lines.size() - 2)->append(l1);
  }

  Version++;
}
<|endoftext|>


<commit_before>#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <utility>
#include <regex>

const std::vector<std::pair<std::string, std::string> >ebnf_cont_str = {
	std::pair<std::string, std::string>("(*","*)"), //Comment
	std::pair<std::string, std::string>("\"","\""), //Quote (double)
	std::pair<std::string, std::string>("'","'"),   //Quote (single)
	std::pair<std::string, std::string>("(",")"),   //Group
	std::pair<std::string, std::string>("[","]"),   //Option
	std::pair<std::string, std::string>("{","}"),   //Repetition
	std::pair<std::string, std::string>("?","?")    //Special
};

//Macros
#define EBNF_S_COMMENT ebnf_cont_str[0]
#define EBNF_S_SINGLEQ ebnf_cont_str[1]
#define EBNF_S_DOUBLEQ ebnf_cont_str[2]
#define EBNF_S_GROUP   ebnf_cont_str[3]
#define EBNF_S_OPTION  ebnf_cont_str[4]
#define EBNF_S_REPEAT  ebnf_cont_str[5]
#define EBNF_S_SPECIAL ebnf_cont_str[6]
#define EBNF_S_ALL ebnf_cont_str

#define EBNF_REGEX_COMMENT "(\\(\\*)(?<=\\(\\*)((|\\v|.)*)(?=\\*\\))(\\*\\))"
#define EBNF_REGEX_IDDECLR "([[:alnum:]]|_)(([[:alnum:]]|_)*)(\\s*)(?=(=)((.|\\n)*)(;))"
#define EBNF_REGEX_TERMSTR "((\")([^\"]*)(\"))|((')([^']*)('))"

struct EBNFTree {
	public:
		static void testProgram();
		/*
			EBNF contaiment strings
		*/

		static bool isContainedBy(const std::string& content, uint_type index, const std::pair<std::string,std::string>& between) {
			/*
				Static function, checks if a character within a string is contained
				between two other specified strings.

				Example: isContainedBy("Hello world", 4,{"l","l"}) would return false
				as the first instance of the containers are ajacent to eachother at
				indexes 2 & 3. If the containment strings were {"ll","w"} then the
				function would return true however as index 4 is between an instace
				of the containers.

				Being between the containers INCLUDES being part of the container
				strings.
			*/

		}

		static uint_type skipThrough(const std::string& content, uint_type index, const std::pair<std::string,std::string>& between) {
			/*
				Static function, moves the index integer to an index outside of
				the container strings if it is between an instance. Returns the
				next index outside of the container strings.
			*/
			if (isContainedBy(content,index,between)) {
				return skipThrough(content,content.find(std::get<1>(between), index) + std::get<1>(between).size(),between);
			}
			else {
				return index;
			}
		}

		bool loadIdentifiers(const std::string& content) {
			/*
				Member for loading identifiers into the object, returns true if loading
				was successful, false if there were any syntactic problems with
			*/
			/*
				Valid identifiers will not be within a terminal string or comment and
				be immmediately preceded by either a space or a "=" also not commented
				or within a terminal string.
			*/
			static std::vector<std::pair<std::string,std::string> > notBeWithin = {EBNF_S_COMMENT, EBNF_S_DOUBLEQ, EBNF_S_SINGLEQ};
			std::vector<std::string> identifiers;
			uint_type index = 0;
			do {
				for (uint_type i = 0; i < notBeWithin.size(); i++) {
					index = skipThrough(content,index,notBeWithin[i]);
				}

			} while (false);

			return true;
		}

		bool loadEBNF(const std::string& content) {
			/*
				Member for loading a string representing an EBNF grammar into the
				object.
			*/
			//First check the string has content.
			if (content.size() == 0) {
				std::cerr << "(EBNF interpreter) Error: string is empty, cannot read." << std::endl;
				return false;
			}
			//Find identifiers
			this->loadIdentifiers("(**)");

			return false;
		}
		std::map<std::string, std::string> id_rule_map;
};

void EBNFTree::testProgram() {
	std::string str1 = "(*This is a comment*) abcd";
	std::cout << "for string \"" << str1 << "\" the areas that count as contained by comments are:" << std::endl;
	std::cout << str1 << std::endl;
	for (uint_type i = 0; i < str1.size(); i++) {
		std::cout << EBNFTree::isContainedBy(str1,i,EBNF_S_COMMENT);
	}
	std::cout << std::endl;
}
<commit_msg>Continued work on EBNFTree object std::regex continues to be a problem, trying to figure out the bounds of it<commit_after>#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <utility>
#include <regex>
#include <sstream>

#ifndef PARSE_TYPE_DEFAULTS
#define PARSE_TYPE_DEFAULTS
typedef uintmax_t uint_type;
typedef double prec_type;
#endif

const std::vector<std::pair<std::string, std::string> >ebnf_cont_str = {
	std::pair<std::string, std::string>("(*","*)"), //Comment
	std::pair<std::string, std::string>("\"","\""), //Quote (double)
	std::pair<std::string, std::string>("'","'"),   //Quote (single)
	std::pair<std::string, std::string>("(",")"),   //Group
	std::pair<std::string, std::string>("[","]"),   //Option
	std::pair<std::string, std::string>("{","}"),   //Repetition
	std::pair<std::string, std::string>("?","?")    //Special
};

//Macros
#define EBNF_S_COMMENT ebnf_cont_str[0]
#define EBNF_S_SINGLEQ ebnf_cont_str[1]
#define EBNF_S_DOUBLEQ ebnf_cont_str[2]
#define EBNF_S_GROUP   ebnf_cont_str[3]
#define EBNF_S_OPTION  ebnf_cont_str[4]
#define EBNF_S_REPEAT  ebnf_cont_str[5]
#define EBNF_S_SPECIAL ebnf_cont_str[6]
#define EBNF_S_ALL ebnf_cont_str

#define REGEX_SPECIAL_CHARS "$^{[(|)]}*+?\\."

#define EBNF_REGEX_COMMENT "(\\(\\*)(?<=\\(\\*)((|\\v|.)*)(?=\\*\\))(\\*\\))"
#define EBNF_REGEX_IDDECLR "(([[:alnum:]]|_)+)(\\s*)(?=(=)((.|\\n)*)(;))"
#define EBNF_REGEX_TERMSTR "((\")([^\"]*)(\"))|((')([^']*)('))"

template<class T1, class T2>
bool oneOf(const T1& item, const T2& container, const uint_type size) {
	for (uint_type i = 0; i < size; i++) {
		if (container[i] == item) return true;
	}
	return false;
}

template<class T1, class T2>
bool oneOf(const T1& item, const T2& container) {
	return oneOf<T1,T2>(item,container,container.size());
}

struct EBNFTree {
	public:

		static bool isRegexSyntaxChar(const char toCheck) {
			return oneOf<char,std::string>(toCheck, REGEX_SPECIAL_CHARS);
		}

		static void testProgram();
		/*
			EBNF contaiment strings
		*/

		static bool isContainedBy(const std::string& content, uint_type index, const std::pair<std::string,std::string>& between) {
			/*
				Static function, checks if a character within a string is contained
				between two other specified strings.

				Example: isContainedBy("Hello world", 4,{"l","l"}) would return false
				as the first instance of the containers are ajacent to eachother at
				indexes 2 & 3. If the containment strings were {"ll","w"} then the
				function would return true however as index 4 is between an instace
				of the containers.

				Being between the containers INCLUDES being part of the container
				strings.
			*/
			/*

			*/
			std::string lhs, rhs;
			for (uint_type i = 0; i < std::get<0>(between).size(); i++) {
				if (isRegexSyntaxChar(std::get<0>(between)[i])) lhs += '\\';
				lhs += std::get<0>(between)[i];
			}
			for (uint_type i = 0; i < std::get<1>(between).size(); i++) {
				if (isRegexSyntaxChar(std::get<1>(between)[i])) rhs += '\\';
				rhs += std::get<1>(between)[i];
			}
			std::stringstream regex_stream;
			regex_stream << "(())" ;//"(?<=" << lhs << ")((.|\\n)*)(?=" << rhs << ")";
			try {
				std::regex reg(regex_stream.str(), std::regex_constants::extended);
				std::smatch regm;
				if (std::regex_match(content,regm,reg)) {
					for (uint_type i = 0; i < regm.size(); i++) {
						if (regm.position(i) <= index && index <= uint_type(regm.position(i) + regm.length(i))) {
							return true;
						}
					}
				}
				else {
					return false;
				}
			}
			catch (std::regex_error& err) {
				std::cout << "could not process regex:\n" << regex_stream.str() << "\nreason given: \n" << err.what() << std::endl;
				for (uint_type i = 0; i < regex_stream.str().size(); i++) {
					std::cout << "char @ " << i << " is " << regex_stream.str()[i] << " as " << uint_type(regex_stream.str()[i]) << std::endl;
				}
				exit(-1);
			}
			return false;
		}

		static uint_type skipThrough(const std::string& content, uint_type index, const std::pair<std::string,std::string>& between) {
			/*
				Static function, moves the index integer to an index outside of
				the container strings if it is between an instance. Returns the
				next index outside of the container strings.
			*/
			if (isContainedBy(content,index,between)) {
				return skipThrough(content,content.find(std::get<1>(between), index) + std::get<1>(between).size(),between);
			}
			else {
				return index;
			}
		}

		bool loadIdentifiers(const std::string& content) {
			/*
				Member for loading identifiers into the object, returns true if loading
				was successful, false if there were any syntactic problems with
			*/
			/*
				Valid identifiers will not be within a terminal string or comment and
				be immmediately preceded by either a space or a "=" also not commented
				or within a terminal string.
			*/
			static std::vector<std::pair<std::string,std::string> > notBeWithin = {EBNF_S_COMMENT, EBNF_S_DOUBLEQ, EBNF_S_SINGLEQ};
			std::vector<std::string> identifiers;
			uint_type index = 0;
			do {
				for (uint_type i = 0; i < notBeWithin.size(); i++) {
					index = skipThrough(content,index,notBeWithin[i]);
				}

			} while (false);

			return true;
		}

		bool loadEBNF(const std::string& content) {
			/*
				Member for loading a string representing an EBNF grammar into the
				object.
			*/
			//First check the string has content.
			if (content.size() == 0) {
				std::cerr << "(EBNF interpreter) Error: string is empty, cannot read." << std::endl;
				return false;
			}
			//Find identifiers
			this->loadIdentifiers("(**)");

			return false;
		}
		std::map<std::string, std::string> id_rule_map;
};

void EBNFTree::testProgram() {
	std::string str1 = "(* This is a comment *) \"A string! abcd.\"";
	std::cout << "for string \"" << str1 << "\" the areas that count as contained by comments are:" << std::endl;
	std::cout << str1 << std::endl;
	for (uint_type i = 0; i < str1.size(); i++) {
		std::cout << EBNFTree::isContainedBy(str1,i,EBNF_S_COMMENT);
	}
	std::cout << std::endl;
}
<|endoftext|>


<commit_before>#include "ScriptEngine.h"
#include "LogHandler.h"
#include "libs/StringManager.h"

#include <vector>
#include <fstream>

using namespace std;
typedef StringManager STR;

std::map<std::string, std::function<void(lua_State *, va_list *)>> ScriptEngine::m_push_lua_param;

ScriptEngine::ScriptEngine()
{
	if (m_push_lua_param.empty())
	{
		m_push_lua_param["nil"] = [](lua_State * L, va_list *ap) { lua_pushnil(L); };
		m_push_lua_param["bool"] = [](lua_State * L, va_list *ap) { int val = va_arg((*ap), bool); lua_pushboolean(L, val); };
		m_push_lua_param["int"] = [](lua_State * L, va_list *ap) { lua_Integer val = va_arg((*ap), int); lua_pushinteger(L, val); };
		m_push_lua_param["float"] = [](lua_State * L, va_list *ap) { lua_Number val = va_arg((*ap), double); lua_pushnumber(L, val); };
		m_push_lua_param["string"] = [](lua_State * L, va_list *ap) { char * val = va_arg((*ap), char *); lua_pushlstring(L, val, strlen(val)); };
	}
	m_lua_state = luaL_newstate();
	luaopen_base(m_lua_state);

	init();
}

ScriptEngine::~ScriptEngine()
{
	clearRetValues();
	lua_close(m_lua_state);
}

void ScriptEngine::init()
{
	// 创建表
	lua_newtable(m_lua_state);
	lua_setglobal(m_lua_state, "__Battle");

	// 添加函数
	lua_getglobal(m_lua_state, "__Battle");

	lua_pushcfunction(m_lua_state, [](lua_State * L)->int { printf("what the fuck!!!"); return 0; });
	lua_setfield(m_lua_state, -2, "Fuck");
}

bool ScriptEngine::loadScript(const char * script, const char * name)
{
	if (luaAssert(luaL_loadbuffer(m_lua_state, script, strlen(script), name), lua_gettop(m_lua_state), "ScriptEngine::loadScript", __LINE__))
		return luaAssert(lua_pcall(m_lua_state, 0, LUA_MULTRET, 0), lua_gettop(m_lua_state), "ScriptEngine::loadScript", __LINE__);
	return false;
}

bool ScriptEngine::loadScriptFromFile(const char * filename)
{
	if (luaAssert(luaL_loadfile(m_lua_state, filename), lua_gettop(m_lua_state), "ScriptEngine::loadScriptFromFile", __LINE__))
		return luaAssert(lua_pcall(m_lua_state, 0, LUA_MULTRET, 0), lua_gettop(m_lua_state), "ScriptEngine::loadScriptFromFile", __LINE__);
	return false;
}

bool ScriptEngine::luaCall(const char * funname, va_list ap)
{
	int ret_index = lua_gettop(m_lua_state);

	vector<string> list;
	STR::split(list, funname, ' ', ',', '(', ')', '\t', '\r', '\n', 0);

	auto it = list.begin();
	vector<string> list_ele;
	STR::split(list_ele, it->c_str(), '.', 0); it++;
	auto it_ele = list_ele.begin();
	auto cur_table = it_ele->c_str();
	lua_getglobal(m_lua_state, cur_table); it_ele++;
	while (it_ele != list_ele.end())
	{
		int cur_top = lua_gettop(m_lua_state);
		if (!lua_istable(m_lua_state, cur_top))
		{
			LogError("ScriptEngine::luaCall", STR::format("lua error: element \"%s\" is not a table!", cur_table));
			lua_pop(m_lua_state, cur_top - ret_index);
			return false;
		}
		cur_table = it_ele->c_str();
		lua_getfield(m_lua_state, -1, it_ele->c_str()); it_ele++;
		lua_remove(m_lua_state, cur_top);
	}

	int count = 0;
	while (it != list.end())
	{
    m_push_lua_param[it->c_str()](m_lua_state, (va_list*)&ap); it++;
		count++;
	}

	if (luaAssert(lua_pcall(m_lua_state, count, LUA_MULTRET, 0), ret_index, "ScriptEngine::luaCall", __LINE__))
	{
		auto cur_index = lua_gettop(m_lua_state);
		clearRetValues();
		for (int i = ret_index + 1; i <= cur_index; i++)
			m_retval_arr.push_back(luaGetValue(i));
		return true;
	}
	return false;
}

bool ScriptEngine::luaCall(const char * funname, ...)
{
	va_list ap;
	va_start(ap, funname);
	auto ret = luaCall(funname, ap);
	va_end(ap);
	return ret;
}

bool ScriptEngine::luaAddTable(const char * name, const char * parentName)
{
	if (parentName == std::string("_G"))
	{
		lua_newtable(m_lua_state);
		lua_setglobal(m_lua_state, name);
	}
	else
	{
		auto ret_index = lua_gettop(m_lua_state);

		vector<string> list_ele;
		STR::split(list_ele, parentName, '.', 0);
		auto it_ele = list_ele.begin();

		auto cur_table = it_ele->c_str();
		lua_getglobal(m_lua_state, cur_table); it_ele++;
		if (!lua_istable(m_lua_state, lua_gettop(m_lua_state)))
		{
			LogError("ScriptEngine::luaAddTable", STR::format("lua error: element \"%s\" is not a table!", cur_table));
			lua_pop(m_lua_state, 1);
			return false;
		}

		while (it_ele != list_ele.end())
		{
			int cur_top = lua_gettop(m_lua_state);
			if (!lua_istable(m_lua_state, cur_top))
			{
				LogError("ScriptEngine::luaAddTable", STR::format("lua error: element \"%s\" is not a table!", cur_table));
				lua_pop(m_lua_state, cur_top - ret_index);
				return false;
			}
			cur_table = it_ele->c_str();
			lua_getfield(m_lua_state, -1, it_ele->c_str()); it_ele++;
		}
		lua_setfield(m_lua_state, -1, name);

		lua_pop(m_lua_state, lua_gettop(m_lua_state) - ret_index);
	}
	return true;
}

bool ScriptEngine::luaAddFunction(const char * name, lua_CFunction func, const char * parentName)
{
	return false;
}

int ScriptEngine::getFileSize(const char * filePath)
{
	std::ifstream file;
	file.open(filePath, ios::binary);
	if (!file.is_open()) LogWarn("ScriptEngine::getFileSize", STR::format("file \"%s\" can not open!", filePath));

	file.seekg(0, std::ios::end);
	auto ret = (int)file.tellg();
	file.close();

	return ret;
}

uTypeUnion ScriptEngine::luaGetValue(int index)
{
	uTypeUnion ret;
	ret.int64Val = 0;
	switch (lua_type(m_lua_state, index))
	{
		case LUA_TNIL:
			ret.int64Val = 0;
			break;
		case LUA_TNUMBER:
			ret.doubleVal = lua_tonumber(m_lua_state, index);
			break;
		case LUA_TBOOLEAN:
			ret.intVal[0] = lua_toboolean(m_lua_state, index);
			break;
		case LUA_TSTRING:
			{
				m_retval_strings.push_back(lua_tostring(m_lua_state, index));
				ret.ptrVal[0] = (void *)m_retval_strings.back().c_str();
			}
			break;
		default:
			break;
	}
	return ret;
}

bool ScriptEngine::luaAssert(int res, int tindex, const char* tag, int lineNum)
{
	switch (res)
	{
		case LUA_OK	:
			return true;
		case LUA_YIELD:
		case LUA_ERRRUN:
		case LUA_ERRSYNTAX:
		case LUA_ERRMEM:
		case LUA_ERRGCMM:
		case LUA_ERRERR:
		default:
			{
				int top = lua_gettop(m_lua_state);
				while (top > tindex)
				{
          LogHandler::setLog(tag, STR::format("lua error: %s", lua_tolstring(m_lua_state, top, nullptr)), eLogType::Error, __FILE__, lineNum);
					lua_pop(m_lua_state, 1);
					top = lua_gettop(m_lua_state);
				}
			}
			break;
	}
	return false;
}

bool ScriptEngine::luaGetTableToStackTop(const char * tableName)
{
	auto ret_index = lua_gettop(m_lua_state);

	vector<string> list_ele;
	STR::split(list_ele, tableName, '.', 0);
	auto it_ele = list_ele.begin();

	auto cur_table = it_ele->c_str();
	lua_getglobal(m_lua_state, cur_table); it_ele++;
	if (!lua_istable(m_lua_state, lua_gettop(m_lua_state)))
	{
		LogError("ScriptEngine::luaAddTable", STR::format("lua error: element \"%s\" is not a table!", cur_table));
		lua_pop(m_lua_state, 1);
		return false;
	}

	while (it_ele != list_ele.end())
	{
		int cur_top = lua_gettop(m_lua_state);
		if (!lua_istable(m_lua_state, cur_top))
		{
			LogError("ScriptEngine::luaAddTable", STR::format("lua error: element \"%s\" is not a table!", cur_table));
			lua_pop(m_lua_state, cur_top - ret_index);
			return false;
		}
		cur_table = it_ele->c_str();
		lua_getfield(m_lua_state, -1, it_ele->c_str()); it_ele++;
	}
}
<commit_msg>Revert "Revert "commit""<commit_after>#include "ScriptEngine.h"
#include "LogHandler.h"
#include "libs/StringManager.h"

#include <vector>
#include <fstream>

using namespace std;
typedef StringManager STR;

std::map<std::string, std::function<void(lua_State *, va_list *)>> ScriptEngine::m_push_lua_param;

ScriptEngine::ScriptEngine()
{
	if (m_push_lua_param.empty())
	{
		m_push_lua_param["nil"] = [](lua_State * L, va_list *ap) { lua_pushnil(L); };
		m_push_lua_param["bool"] = [](lua_State * L, va_list *ap) { int val = va_arg((*ap), bool); lua_pushboolean(L, val); };
		m_push_lua_param["int"] = [](lua_State * L, va_list *ap) { lua_Integer val = va_arg((*ap), int); lua_pushinteger(L, val); };
		m_push_lua_param["float"] = [](lua_State * L, va_list *ap) { lua_Number val = va_arg((*ap), double); lua_pushnumber(L, val); };
		m_push_lua_param["string"] = [](lua_State * L, va_list *ap) { char * val = va_arg((*ap), char *); lua_pushlstring(L, val, strlen(val)); };
	}
	m_lua_state = luaL_newstate();
	luaopen_base(m_lua_state);

	init();
}

ScriptEngine::~ScriptEngine()
{
	clearRetValues();
	lua_close(m_lua_state);
}

void ScriptEngine::init()
{
	// 创建表
	lua_newtable(m_lua_state);
	lua_setglobal(m_lua_state, "__Battle");

	// 添加函数
	lua_getglobal(m_lua_state, "__Battle");

	lua_pushcfunction(m_lua_state, [](lua_State * L)->int { printf("what the fuck!!!"); return 0; });
	lua_setfield(m_lua_state, -2, "Fuck");
}

bool ScriptEngine::loadScript(const char * script, const char * name)
{
	if (luaAssert(luaL_loadbuffer(m_lua_state, script, strlen(script), name), lua_gettop(m_lua_state), "ScriptEngine::loadScript", __LINE__))
		return luaAssert(lua_pcall(m_lua_state, 0, LUA_MULTRET, 0), lua_gettop(m_lua_state), "ScriptEngine::loadScript", __LINE__);
	return false;
}

bool ScriptEngine::loadScriptFromFile(const char * filename)
{
	if (luaAssert(luaL_loadfile(m_lua_state, filename), lua_gettop(m_lua_state), "ScriptEngine::loadScriptFromFile", __LINE__))
		return luaAssert(lua_pcall(m_lua_state, 0, LUA_MULTRET, 0), lua_gettop(m_lua_state), "ScriptEngine::loadScriptFromFile", __LINE__);
	return false;
}

bool ScriptEngine::luaCall(const char * funname, va_list ap)
{
	int ret_index = lua_gettop(m_lua_state);

	vector<string> list;
	STR::split(list, funname, ' ', ',', '(', ')', '\t', '\r', '\n', 0);

	auto it = list.begin();
	vector<string> list_ele;
	STR::split(list_ele, it->c_str(), '.', 0); it++;
	auto it_ele = list_ele.begin();
	auto cur_table = it_ele->c_str();
	lua_getglobal(m_lua_state, cur_table); it_ele++;
	while (it_ele != list_ele.end())
	{
		int cur_top = lua_gettop(m_lua_state);
		if (!lua_istable(m_lua_state, cur_top))
		{
			LogError("ScriptEngine::luaCall", STR::format("lua error: element \"%s\" is not a table!", cur_table));
			lua_pop(m_lua_state, cur_top - ret_index);
			return false;
		}
		cur_table = it_ele->c_str();
		lua_getfield(m_lua_state, -1, it_ele->c_str()); it_ele++;
		lua_remove(m_lua_state, cur_top);
	}

	int count = 0;
	while (it != list.end())
	{
    m_push_lua_param[it->c_str()](m_lua_state, (va_list*)&ap); it++;
		count++;
	}

	if (luaAssert(lua_pcall(m_lua_state, count, LUA_MULTRET, 0), ret_index, "ScriptEngine::luaCall", __LINE__))
	{
		auto cur_index = lua_gettop(m_lua_state);
		clearRetValues();
		for (int i = ret_index + 1; i <= cur_index; i++)
			m_retval_arr.push_back(luaGetValue(i));
		return true;
	}
	return false;
}

bool ScriptEngine::luaCall(const char * funname, ...)
{
	va_list ap;
	va_start(ap, funname);
	auto ret = luaCall(funname, ap);
	va_end(ap);
	return ret;
}

bool ScriptEngine::luaAddTable(const char * name, const char * parentName)
{
	if (parentName == std::string("_G"))
	{
		lua_newtable(m_lua_state);
		lua_setglobal(m_lua_state, name);
	}
	else
	{
		auto ret_index = lua_gettop(m_lua_state);

		vector<string> list_ele;
		STR::split(list_ele, parentName, '.', 0);
		auto it_ele = list_ele.begin();

		auto cur_table = it_ele->c_str();
		lua_getglobal(m_lua_state, cur_table); it_ele++;
		if (!lua_istable(m_lua_state, lua_gettop(m_lua_state)))
		{
			LogError("ScriptEngine::luaAddTable", STR::format("lua error: element \"%s\" is not a table!", cur_table));
			lua_pop(m_lua_state, 1);
			return false;
		}

		while (it_ele != list_ele.end())
		{
			int cur_top = lua_gettop(m_lua_state);
			if (!lua_istable(m_lua_state, cur_top))
			{
				LogError("ScriptEngine::luaAddTable", STR::format("lua error: element \"%s\" is not a table!", cur_table));
				lua_pop(m_lua_state, cur_top - ret_index);
				return false;
			}
			cur_table = it_ele->c_str();
			lua_getfield(m_lua_state, -1, it_ele->c_str()); it_ele++;
		}
		lua_setfield(m_lua_state, -1, name);

		lua_pop(m_lua_state, lua_gettop(m_lua_state) - ret_index);
	}
	return true;
}

bool ScriptEngine::luaAddFunction(const char * name, lua_CFunction func, const char * parentName)
{
	return false;
}

int ScriptEngine::getFileSize(const char * filePath)
{
	std::ifstream file;
	file.open(filePath, ios::binary);
	if (!file.is_open()) LogWarn("ScriptEngine::getFileSize", STR::format("file \"%s\" can not open!", filePath));

	file.seekg(0, std::ios::end);
	auto ret = (int)file.tellg();
	file.close();

	return ret;
}

uTypeUnion ScriptEngine::luaGetValue(int index)
{
	uTypeUnion ret;
	ret.int64Val = 0;
	switch (lua_type(m_lua_state, index))
	{
		case LUA_TNIL:
			ret.int64Val = 0;
			break;
		case LUA_TNUMBER:
			ret.doubleVal = lua_tonumber(m_lua_state, index);
			break;
		case LUA_TBOOLEAN:
			ret.intVal[0] = lua_toboolean(m_lua_state, index);
			break;
		case LUA_TSTRING:
			{
				m_retval_strings.push_back(lua_tostring(m_lua_state, index));
				ret.ptrVal[0] = (void *)m_retval_strings.back().c_str();
			}
			break;
		default:
			break;
	}
	return ret;
}

bool ScriptEngine::luaAssert(int res, int tindex, const char* tag, int lineNum)
{
	switch (res)
	{
		case LUA_OK	:
			return true;
		case LUA_YIELD:
		case LUA_ERRRUN:
		case LUA_ERRSYNTAX:
		case LUA_ERRMEM:
		case LUA_ERRGCMM:
		case LUA_ERRERR:
		default:
			{
				int top = lua_gettop(m_lua_state);
				while (top > tindex)
				{
          LogHandler::setLog(tag, STR::format("lua error: %s", lua_tolstring(m_lua_state, top, nullptr)), eLogType::Error, __FILE__, lineNum);
					lua_pop(m_lua_state, 1);
					top = lua_gettop(m_lua_state);
				}
			}
			break;
	}
	return false;
}

bool ScriptEngine::luaGetTableToStackTop(const char * tableName)
{
	auto ret_index = lua_gettop(m_lua_state);

	vector<string> list_ele;
	STR::split(list_ele, tableName, '.', 0);
	auto it_ele = list_ele.begin();

	auto cur_table = it_ele->c_str();
	lua_getglobal(m_lua_state, cur_table); it_ele++;
	if (!lua_istable(m_lua_state, lua_gettop(m_lua_state)))
	{
		LogError("ScriptEngine::luaAddTable", STR::format("lua error: element \"%s\" is not a table!", cur_table));
		lua_pop(m_lua_state, 1);
		return false;
	}

	while (it_ele != list_ele.end())
	{
		int cur_top = lua_gettop(m_lua_state);
		if (!lua_istable(m_lua_state, cur_top))
		{
			LogError("ScriptEngine::luaAddTable", STR::format("lua error: element \"%s\" is not a table!", cur_table));
			lua_pop(m_lua_state, cur_top - ret_index);
			return false;
		}
		cur_table = it_ele->c_str();
		lua_getfield(m_lua_state, -1, it_ele->c_str()); it_ele++;
	}

  return true;
}

<|endoftext|>


<commit_before>#include <getopt.h>
#include <stdio.h>
#include <string.h>

#include <algorithm>

#include "fsck/checker.hpp"
#include "logger.hpp"
#include "utils.hpp"
#include "help.hpp"

namespace fsck {

// TODO: Should this still be UNUSED?
void usage(UNUSED const char *name) {
    help_pager_t *help = help_pager_t::instance();
    help->pagef("Usage:\n"
                "        rethinkdb fsck [OPTIONS] -f <file_1> [-f <file_2> ...] [--metadata-file <file>]\n");
    help->pagef("\n"
                "Options:\n"
                "  -f  --file                Path to file or block device where part or all of\n"
                "                            the database exists.\n"
                "      --metadata-file       Path to the file where the database metadata exists\n"
                "      --ignore-diff-log     Do not apply patches from the diff log while\n"
                "                            checking the database.\n");
    help->pagef("\n"
                "Output options:\n"
                "  -l  --log-file            File to log to.  If not provided, messages will be\n"
                "                            printed to stderr.\n");
#ifndef NDEBUG
    help->pagef("  -c  --command-line        Print the command line arguments that were used\n"
                "                            to start this server.\n");
#endif
    help->pagef("\n"
                "Fsck is used to check one or more files for consistency\n");
    exit(0);
}

enum { ignore_diff_log = 256,  // Start these values above the ASCII range.
       metadata_file,
};

void parse_cmd_args(int argc, char **argv, config_t *config) {
    // TODO disallow rogue options.

    optind = 1;  // reinit getopt.
    if (argc >= 2) {
        if (!strncmp("help", argv[1], 4)) {
            usage(argv[0]);
        }
    }
    for (;;) {
        int do_help = 0;
        int command_line = 0;
        int extract_version = 0;
        static const struct option long_options[] =
            {
                {"file", required_argument, 0, 'f'},
                {"metadata-file", required_argument, 0, metadata_file},
                {"ignore-diff-log", no_argument, 0, ignore_diff_log},
                {"log-file", required_argument, 0, 'l'},
                {"help", no_argument, &do_help, 1},
                {"command-line", no_argument, &command_line, 'c'},
                {"version", no_argument, &extract_version, 'v'},
                {0, 0, 0, 0}
            };

        int option_index = 0;
        int c = getopt_long(argc, argv, "f:l:hcv", long_options, &option_index);

        if (do_help) {
            c = 'h';
        }

        if(command_line) {
            c = 'c';
        }

        if (extract_version) {
            c = 'v';
        }

        // Detect the end of the options.
        if (c == -1)
            break;

        switch (c) {
        case 0:
            break;
        case 'f':
            config->input_filenames.push_back(optarg);
            break;
        case metadata_file:
            config->metadata_filename = std::string(optarg);
            break;
        case ignore_diff_log:
            config->ignore_diff_log = true;
            break;
        case 'l':
            config->log_file_name = optarg;
            break;
        case 'c':
            config->print_command_line = true;
            break;
        case 'v':
            config->print_file_version = true;
            break;
        case 'h':
            usage(argv[0]);
            break;
        default:
            // getopt_long already printed an error message.
            usage(argv[0]);
        }
    }

    if (optind < argc) {
        fail_due_to_user_error("Unexpected extra argument: \"%s\"", argv[optind]);
    }

    // Sanity checks

    if (config->input_filenames.empty()) {
        fprintf(stderr, "Please specify some files.\n");
        usage(argv[0]);
    }

    {
        std::vector<std::string> names = config->input_filenames;
        std::sort(names.begin(), names.end());
        if (std::unique(names.begin(), names.end()) != names.end()) {
            fail_due_to_user_error("Duplicate file names provided.");
        }
    }
}

}  // namespace fsck

int run_fsck(int argc, char **argv) {
    fsck::config_t config;
    fsck::parse_cmd_args(argc, argv, &config);

    if (config.log_file_name != "") {
        // log_file = fopen(config.log_file_name.c_str(), "w");
    }

    if (check_files(&config)) {
        return EXIT_SUCCESS;
    } else {
        return EXIT_FAILURE;
    }
}
<commit_msg>Added logging to fsck/fsck.cc<commit_after>#include <getopt.h>
#include <stdio.h>
#include <string.h>

#include <algorithm>

#include "fsck/checker.hpp"
#include "logger.hpp"
#include "utils.hpp"
#include "help.hpp"

namespace fsck {

// TODO: Should this still be UNUSED?
void usage(UNUSED const char *name) {
    help_pager_t *help = help_pager_t::instance();
    help->pagef("Usage:\n"
                "        rethinkdb fsck [OPTIONS] -f <file_1> [-f <file_2> ...] [--metadata-file <file>]\n");
    help->pagef("\n"
                "Options:\n"
                "  -f  --file                Path to file or block device where part or all of\n"
                "                            the database exists.\n"
                "      --metadata-file       Path to the file where the database metadata exists\n"
                "      --ignore-diff-log     Do not apply patches from the diff log while\n"
                "                            checking the database.\n");
    help->pagef("\n"
                "Output options:\n"
                "  -l  --log-file            File to log to.  If not provided, messages will be\n"
                "                            printed to stderr.\n");
#ifndef NDEBUG
    help->pagef("  -c  --command-line        Print the command line arguments that were used\n"
                "                            to start this server.\n");
#endif
    help->pagef("\n"
                "Fsck is used to check one or more files for consistency\n");
    exit(0);
}

enum { ignore_diff_log = 256,  // Start these values above the ASCII range.
       metadata_file,
};

void parse_cmd_args(int argc, char **argv, config_t *config) {
    // TODO disallow rogue options.

    optind = 1;  // reinit getopt.
    if (argc >= 2) {
        if (!strncmp("help", argv[1], 4)) {
            usage(argv[0]);
        }
    }
    for (;;) {
        int do_help = 0;
        int command_line = 0;
        int extract_version = 0;
        static const struct option long_options[] =
            {
                {"file", required_argument, 0, 'f'},
                {"metadata-file", required_argument, 0, metadata_file},
                {"ignore-diff-log", no_argument, 0, ignore_diff_log},
                {"log-file", required_argument, 0, 'l'},
                {"help", no_argument, &do_help, 1},
                {"command-line", no_argument, &command_line, 'c'},
                {"version", no_argument, &extract_version, 'v'},
                {0, 0, 0, 0}
            };

        int option_index = 0;
        int c = getopt_long(argc, argv, "f:l:hcv", long_options, &option_index);

        if (do_help) {
            c = 'h';
        }

        if(command_line) {
            c = 'c';
        }

        if (extract_version) {
            c = 'v';
        }

        // Detect the end of the options.
        if (c == -1)
            break;

        switch (c) {
        case 0:
            break;
        case 'f':
            config->input_filenames.push_back(optarg);
            break;
        case metadata_file:
            config->metadata_filename = std::string(optarg);
            break;
        case ignore_diff_log:
            config->ignore_diff_log = true;
            break;
        case 'l':
            config->log_file_name = optarg;
            break;
        case 'c':
            config->print_command_line = true;
            break;
        case 'v':
            config->print_file_version = true;
            break;
        case 'h':
            usage(argv[0]);
            break;
        default:
            // getopt_long already printed an error message.
            usage(argv[0]);
        }
    }

    if (optind < argc) {
        fail_due_to_user_error("Unexpected extra argument: \"%s\"", argv[optind]);
    }

    // Sanity checks

    if (config->input_filenames.empty()) {
        logSTDERR("Please specify some files.\n");
        usage(argv[0]);
    }

    {
        std::vector<std::string> names = config->input_filenames;
        std::sort(names.begin(), names.end());
        if (std::unique(names.begin(), names.end()) != names.end()) {
            fail_due_to_user_error("Duplicate file names provided.");
        }
    }
}

}  // namespace fsck

int run_fsck(int argc, char **argv) {
    fsck::config_t config;
    fsck::parse_cmd_args(argc, argv, &config);

    if (config.log_file_name != "") {
        // log_file = fopen(config.log_file_name.c_str(), "w");
    }

    if (check_files(&config)) {
        return EXIT_SUCCESS;
    } else {
        return EXIT_FAILURE;
    }
}
<|endoftext|>