mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-06-16 07:07:13 +02:00
Dumped the old implementation. Started with a more simple approach.
This commit is contained in:
253
external/Common/posix.cc
vendored
253
external/Common/posix.cc
vendored
@ -1,253 +0,0 @@
|
||||
/*
|
||||
A C++ interface to POSIX functions.
|
||||
|
||||
Copyright (c) 2014 - 2015, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. 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.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// Disable bogus MSVC warnings.
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "posix.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
|
||||
# define O_CREAT _O_CREAT
|
||||
# define O_TRUNC _O_TRUNC
|
||||
|
||||
# ifndef S_IRUSR
|
||||
# define S_IRUSR _S_IREAD
|
||||
# endif
|
||||
|
||||
# ifndef S_IWUSR
|
||||
# define S_IWUSR _S_IWRITE
|
||||
# endif
|
||||
|
||||
# ifdef __MINGW32__
|
||||
# define _SH_DENYNO 0x40
|
||||
# undef fileno
|
||||
# endif
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
namespace {
|
||||
#ifdef _WIN32
|
||||
// Return type of read and write functions.
|
||||
typedef int RWResult;
|
||||
|
||||
// On Windows the count argument to read and write is unsigned, so convert
|
||||
// it from size_t preventing integer overflow.
|
||||
inline unsigned convert_rwcount(std::size_t count) {
|
||||
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
|
||||
}
|
||||
#else
|
||||
// Return type of read and write functions.
|
||||
typedef ssize_t RWResult;
|
||||
|
||||
inline std::size_t convert_rwcount(std::size_t count) { return count; }
|
||||
#endif
|
||||
}
|
||||
|
||||
fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT {
|
||||
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
|
||||
fmt::report_system_error(errno, "cannot close file");
|
||||
}
|
||||
|
||||
fmt::BufferedFile::BufferedFile(
|
||||
fmt::CStringRef filename, fmt::CStringRef mode) {
|
||||
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);
|
||||
if (!file_)
|
||||
throw SystemError(errno, "cannot open file {}", filename);
|
||||
}
|
||||
|
||||
void fmt::BufferedFile::close() {
|
||||
if (!file_)
|
||||
return;
|
||||
int result = FMT_SYSTEM(fclose(file_));
|
||||
file_ = 0;
|
||||
if (result != 0)
|
||||
throw SystemError(errno, "cannot close file");
|
||||
}
|
||||
|
||||
// A macro used to prevent expansion of fileno on broken versions of MinGW.
|
||||
#define FMT_ARGS
|
||||
|
||||
int fmt::BufferedFile::fileno() const {
|
||||
int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
|
||||
if (fd == -1)
|
||||
throw SystemError(errno, "cannot get file descriptor");
|
||||
return fd;
|
||||
}
|
||||
|
||||
fmt::File::File(fmt::CStringRef path, int oflag) {
|
||||
int mode = S_IRUSR | S_IWUSR;
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
fd_ = -1;
|
||||
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
|
||||
#else
|
||||
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
|
||||
#endif
|
||||
if (fd_ == -1)
|
||||
throw SystemError(errno, "cannot open file {}", path);
|
||||
}
|
||||
|
||||
fmt::File::~File() FMT_NOEXCEPT {
|
||||
// Don't retry close in case of EINTR!
|
||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
|
||||
fmt::report_system_error(errno, "cannot close file");
|
||||
}
|
||||
|
||||
void fmt::File::close() {
|
||||
if (fd_ == -1)
|
||||
return;
|
||||
// Don't retry close in case of EINTR!
|
||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||
int result = FMT_POSIX_CALL(close(fd_));
|
||||
fd_ = -1;
|
||||
if (result != 0)
|
||||
throw SystemError(errno, "cannot close file");
|
||||
}
|
||||
|
||||
fmt::LongLong fmt::File::size() const {
|
||||
#ifdef _WIN32
|
||||
// Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
|
||||
// is less than 0x0500 as is the case with some default MinGW builds.
|
||||
// Both functions support large file sizes.
|
||||
DWORD size_upper = 0;
|
||||
HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
|
||||
DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
|
||||
if (size_lower == INVALID_FILE_SIZE) {
|
||||
DWORD error = GetLastError();
|
||||
if (error != NO_ERROR)
|
||||
throw WindowsError(GetLastError(), "cannot get file size");
|
||||
}
|
||||
fmt::ULongLong long_size = size_upper;
|
||||
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
|
||||
#else
|
||||
typedef struct stat Stat;
|
||||
Stat file_stat = Stat();
|
||||
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
|
||||
throw SystemError(errno, "cannot get file attributes");
|
||||
FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
|
||||
"return type of File::size is not large enough");
|
||||
return file_stat.st_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::size_t fmt::File::read(void *buffer, std::size_t count) {
|
||||
RWResult result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
|
||||
if (result < 0)
|
||||
throw SystemError(errno, "cannot read from file");
|
||||
return result;
|
||||
}
|
||||
|
||||
std::size_t fmt::File::write(const void *buffer, std::size_t count) {
|
||||
RWResult result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
|
||||
if (result < 0)
|
||||
throw SystemError(errno, "cannot write to file");
|
||||
return result;
|
||||
}
|
||||
|
||||
fmt::File fmt::File::dup(int fd) {
|
||||
// Don't retry as dup doesn't return EINTR.
|
||||
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
|
||||
int new_fd = FMT_POSIX_CALL(dup(fd));
|
||||
if (new_fd == -1)
|
||||
throw SystemError(errno, "cannot duplicate file descriptor {}", fd);
|
||||
return File(new_fd);
|
||||
}
|
||||
|
||||
void fmt::File::dup2(int fd) {
|
||||
int result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||
if (result == -1) {
|
||||
throw SystemError(errno,
|
||||
"cannot duplicate file descriptor {} to {}", fd_, fd);
|
||||
}
|
||||
}
|
||||
|
||||
void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT {
|
||||
int result = 0;
|
||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||
if (result == -1)
|
||||
ec = ErrorCode(errno);
|
||||
}
|
||||
|
||||
void fmt::File::pipe(File &read_end, File &write_end) {
|
||||
// Close the descriptors first to make sure that assignments don't throw
|
||||
// and there are no leaks.
|
||||
read_end.close();
|
||||
write_end.close();
|
||||
int fds[2] = {};
|
||||
#ifdef _WIN32
|
||||
// Make the default pipe capacity same as on Linux 2.6.11+.
|
||||
enum { DEFAULT_CAPACITY = 65536 };
|
||||
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
|
||||
#else
|
||||
// Don't retry as the pipe function doesn't return EINTR.
|
||||
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
|
||||
int result = FMT_POSIX_CALL(pipe(fds));
|
||||
#endif
|
||||
if (result != 0)
|
||||
throw SystemError(errno, "cannot create pipe");
|
||||
// The following assignments don't throw because read_fd and write_fd
|
||||
// are closed.
|
||||
read_end = File(fds[0]);
|
||||
write_end = File(fds[1]);
|
||||
}
|
||||
|
||||
fmt::BufferedFile fmt::File::fdopen(const char *mode) {
|
||||
// Don't retry as fdopen doesn't return EINTR.
|
||||
FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
|
||||
if (!f)
|
||||
throw SystemError(errno, "cannot associate stream with file descriptor");
|
||||
BufferedFile file(f);
|
||||
fd_ = -1;
|
||||
return file;
|
||||
}
|
||||
|
||||
long fmt::getpagesize() {
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
return si.dwPageSize;
|
||||
#else
|
||||
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
|
||||
if (size < 0)
|
||||
throw SystemError(errno, "cannot get memory page size");
|
||||
return size;
|
||||
#endif
|
||||
}
|
340
external/Common/posix.h
vendored
340
external/Common/posix.h
vendored
@ -1,340 +0,0 @@
|
||||
/*
|
||||
A C++ interface to POSIX functions.
|
||||
|
||||
Copyright (c) 2014 - 2015, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. 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.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef FMT_POSIX_H_
|
||||
#define FMT_POSIX_H_
|
||||
|
||||
#ifdef __MINGW32__
|
||||
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
|
||||
# undef __STRICT_ANSI__
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h> // for O_RDONLY
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#ifndef FMT_POSIX
|
||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||
// Fix warnings about deprecated symbols.
|
||||
# define FMT_POSIX(call) _##call
|
||||
# else
|
||||
# define FMT_POSIX(call) call
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
|
||||
#ifdef FMT_SYSTEM
|
||||
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
|
||||
#else
|
||||
# define FMT_SYSTEM(call) call
|
||||
# ifdef _WIN32
|
||||
// Fix warnings about deprecated symbols.
|
||||
# define FMT_POSIX_CALL(call) ::_##call
|
||||
# else
|
||||
# define FMT_POSIX_CALL(call) ::call
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if FMT_GCC_VERSION >= 407
|
||||
# define FMT_UNUSED __attribute__((unused))
|
||||
#else
|
||||
# define FMT_UNUSED
|
||||
#endif
|
||||
|
||||
#if FMT_USE_STATIC_ASSERT || FMT_HAS_CPP_ATTRIBUTE(cxx_static_assert) || \
|
||||
(FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600
|
||||
# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)
|
||||
#else
|
||||
# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)
|
||||
# define FMT_STATIC_ASSERT(cond, message) \
|
||||
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
|
||||
#endif
|
||||
|
||||
// Retries the expression while it evaluates to error_result and errno
|
||||
// equals to EINTR.
|
||||
#ifndef _WIN32
|
||||
# define FMT_RETRY_VAL(result, expression, error_result) \
|
||||
do { \
|
||||
result = (expression); \
|
||||
} while (result == error_result && errno == EINTR)
|
||||
#else
|
||||
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
|
||||
#endif
|
||||
|
||||
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
|
||||
|
||||
namespace fmt {
|
||||
|
||||
// An error code.
|
||||
class ErrorCode {
|
||||
private:
|
||||
int value_;
|
||||
|
||||
public:
|
||||
explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {}
|
||||
|
||||
int get() const FMT_NOEXCEPT { return value_; }
|
||||
};
|
||||
|
||||
// A buffered file.
|
||||
class BufferedFile {
|
||||
private:
|
||||
FILE *file_;
|
||||
|
||||
friend class File;
|
||||
|
||||
explicit BufferedFile(FILE *f) : file_(f) {}
|
||||
|
||||
public:
|
||||
// Constructs a BufferedFile object which doesn't represent any file.
|
||||
BufferedFile() FMT_NOEXCEPT : file_(0) {}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
~BufferedFile() FMT_NOEXCEPT;
|
||||
|
||||
#if !FMT_USE_RVALUE_REFERENCES
|
||||
// Emulate a move constructor and a move assignment operator if rvalue
|
||||
// references are not supported.
|
||||
|
||||
private:
|
||||
// A proxy object to emulate a move constructor.
|
||||
// It is private to make it impossible call operator Proxy directly.
|
||||
struct Proxy {
|
||||
FILE *file;
|
||||
};
|
||||
|
||||
public:
|
||||
// A "move constructor" for moving from a temporary.
|
||||
BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
|
||||
|
||||
// A "move constructor" for for moving from an lvalue.
|
||||
BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) {
|
||||
f.file_ = 0;
|
||||
}
|
||||
|
||||
// A "move assignment operator" for moving from a temporary.
|
||||
BufferedFile &operator=(Proxy p) {
|
||||
close();
|
||||
file_ = p.file;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// A "move assignment operator" for moving from an lvalue.
|
||||
BufferedFile &operator=(BufferedFile &other) {
|
||||
close();
|
||||
file_ = other.file_;
|
||||
other.file_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Returns a proxy object for moving from a temporary:
|
||||
// BufferedFile file = BufferedFile(...);
|
||||
operator Proxy() FMT_NOEXCEPT {
|
||||
Proxy p = {file_};
|
||||
file_ = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
#else
|
||||
private:
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
|
||||
|
||||
public:
|
||||
BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) {
|
||||
other.file_ = 0;
|
||||
}
|
||||
|
||||
BufferedFile& operator=(BufferedFile &&other) {
|
||||
close();
|
||||
file_ = other.file_;
|
||||
other.file_ = 0;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Opens a file.
|
||||
BufferedFile(CStringRef filename, CStringRef mode);
|
||||
|
||||
// Closes the file.
|
||||
void close();
|
||||
|
||||
// Returns the pointer to a FILE object representing this file.
|
||||
FILE *get() const FMT_NOEXCEPT { return file_; }
|
||||
|
||||
// We place parentheses around fileno to workaround a bug in some versions
|
||||
// of MinGW that define fileno as a macro.
|
||||
int (fileno)() const;
|
||||
|
||||
void print(CStringRef format_str, const ArgList &args) {
|
||||
fmt::print(file_, format_str, args);
|
||||
}
|
||||
FMT_VARIADIC(void, print, CStringRef)
|
||||
};
|
||||
|
||||
// A file. Closed file is represented by a File object with descriptor -1.
|
||||
// Methods that are not declared with FMT_NOEXCEPT may throw
|
||||
// fmt::SystemError in case of failure. Note that some errors such as
|
||||
// closing the file multiple times will cause a crash on Windows rather
|
||||
// than an exception. You can get standard behavior by overriding the
|
||||
// invalid parameter handler with _set_invalid_parameter_handler.
|
||||
class File {
|
||||
private:
|
||||
int fd_; // File descriptor.
|
||||
|
||||
// Constructs a File object with a given descriptor.
|
||||
explicit File(int fd) : fd_(fd) {}
|
||||
|
||||
public:
|
||||
// Possible values for the oflag argument to the constructor.
|
||||
enum {
|
||||
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
|
||||
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
||||
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
|
||||
};
|
||||
|
||||
// Constructs a File object which doesn't represent any file.
|
||||
File() FMT_NOEXCEPT : fd_(-1) {}
|
||||
|
||||
// Opens a file and constructs a File object representing this file.
|
||||
File(CStringRef path, int oflag);
|
||||
|
||||
#if !FMT_USE_RVALUE_REFERENCES
|
||||
// Emulate a move constructor and a move assignment operator if rvalue
|
||||
// references are not supported.
|
||||
|
||||
private:
|
||||
// A proxy object to emulate a move constructor.
|
||||
// It is private to make it impossible call operator Proxy directly.
|
||||
struct Proxy {
|
||||
int fd;
|
||||
};
|
||||
|
||||
public:
|
||||
// A "move constructor" for moving from a temporary.
|
||||
File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
|
||||
|
||||
// A "move constructor" for for moving from an lvalue.
|
||||
File(File &other) FMT_NOEXCEPT : fd_(other.fd_) {
|
||||
other.fd_ = -1;
|
||||
}
|
||||
|
||||
// A "move assignment operator" for moving from a temporary.
|
||||
File &operator=(Proxy p) {
|
||||
close();
|
||||
fd_ = p.fd;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// A "move assignment operator" for moving from an lvalue.
|
||||
File &operator=(File &other) {
|
||||
close();
|
||||
fd_ = other.fd_;
|
||||
other.fd_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Returns a proxy object for moving from a temporary:
|
||||
// File file = File(...);
|
||||
operator Proxy() FMT_NOEXCEPT {
|
||||
Proxy p = {fd_};
|
||||
fd_ = -1;
|
||||
return p;
|
||||
}
|
||||
|
||||
#else
|
||||
private:
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(File);
|
||||
|
||||
public:
|
||||
File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) {
|
||||
other.fd_ = -1;
|
||||
}
|
||||
|
||||
File& operator=(File &&other) {
|
||||
close();
|
||||
fd_ = other.fd_;
|
||||
other.fd_ = -1;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
~File() FMT_NOEXCEPT;
|
||||
|
||||
// Returns the file descriptor.
|
||||
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
||||
|
||||
// Closes the file.
|
||||
void close();
|
||||
|
||||
// Returns the file size.
|
||||
LongLong size() const;
|
||||
|
||||
// Attempts to read count bytes from the file into the specified buffer.
|
||||
std::size_t read(void *buffer, std::size_t count);
|
||||
|
||||
// Attempts to write count bytes from the specified buffer to the file.
|
||||
std::size_t write(const void *buffer, std::size_t count);
|
||||
|
||||
// Duplicates a file descriptor with the dup function and returns
|
||||
// the duplicate as a file object.
|
||||
static File dup(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
void dup2(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
|
||||
|
||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||
// and writing respectively.
|
||||
static void pipe(File &read_end, File &write_end);
|
||||
|
||||
// Creates a BufferedFile object associated with this file and detaches
|
||||
// this File object from the file.
|
||||
BufferedFile fdopen(const char *mode);
|
||||
};
|
||||
|
||||
// Returns the memory page size.
|
||||
long getpagesize();
|
||||
} // namespace fmt
|
||||
|
||||
#if !FMT_USE_RVALUE_REFERENCES
|
||||
namespace std {
|
||||
// For compatibility with C++98.
|
||||
inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; }
|
||||
inline fmt::File &move(fmt::File &f) { return f; }
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // FMT_POSIX_H_
|
23
external/CppFormat/License.txt
vendored
23
external/CppFormat/License.txt
vendored
@ -1,23 +0,0 @@
|
||||
Copyright (c) 2012 - 2015, Victor Zverovich
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. 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.
|
||||
|
||||
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.
|
1330
external/CppFormat/format.cc
vendored
1330
external/CppFormat/format.cc
vendored
File diff suppressed because it is too large
Load Diff
482
external/IRC/LICENSE
vendored
482
external/IRC/LICENSE
vendored
@ -1,482 +0,0 @@
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library 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
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
388
external/IRC/colors.c
vendored
388
external/IRC/colors.c
vendored
@ -1,388 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#define LIBIRC_COLORPARSER_BOLD (1<<1)
|
||||
#define LIBIRC_COLORPARSER_UNDERLINE (1<<2)
|
||||
#define LIBIRC_COLORPARSER_REVERSE (1<<3)
|
||||
#define LIBIRC_COLORPARSER_COLOR (1<<4)
|
||||
|
||||
#define LIBIRC_COLORPARSER_MAXCOLORS 15
|
||||
|
||||
|
||||
static const char * color_replacement_table[] =
|
||||
{
|
||||
"WHITE",
|
||||
"BLACK",
|
||||
"DARKBLUE",
|
||||
"DARKGREEN",
|
||||
"RED",
|
||||
"BROWN",
|
||||
"PURPLE",
|
||||
"OLIVE",
|
||||
"YELLOW",
|
||||
"GREEN",
|
||||
"TEAL",
|
||||
"CYAN",
|
||||
"BLUE",
|
||||
"MAGENTA",
|
||||
"DARKGRAY",
|
||||
"LIGHTGRAY",
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
static inline void libirc_colorparser_addorcat (char ** destline, unsigned int * destlen, const char * str)
|
||||
{
|
||||
unsigned int len = strlen(str);
|
||||
|
||||
if ( *destline )
|
||||
{
|
||||
strcpy (*destline, str);
|
||||
*destline += len;
|
||||
}
|
||||
else
|
||||
*destlen += len;
|
||||
}
|
||||
|
||||
|
||||
static void libirc_colorparser_applymask (unsigned int * mask,
|
||||
char ** destline, unsigned int * destlen,
|
||||
unsigned int bitmask, const char * start, const char * end)
|
||||
{
|
||||
if ( (*mask & bitmask) != 0 )
|
||||
{
|
||||
*mask &= ~bitmask;
|
||||
libirc_colorparser_addorcat (destline, destlen, end);
|
||||
}
|
||||
else
|
||||
{
|
||||
*mask |= bitmask;
|
||||
libirc_colorparser_addorcat (destline, destlen, start);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void libirc_colorparser_applycolor (unsigned int * mask,
|
||||
char ** destline, unsigned int * destlen,
|
||||
unsigned int colorid, unsigned int bgcolorid)
|
||||
{
|
||||
const char * end = "[/COLOR]";
|
||||
char startbuf[64];
|
||||
|
||||
if ( bgcolorid != 0 )
|
||||
sprintf (startbuf, "[COLOR=%s/%s]", color_replacement_table[colorid], color_replacement_table[bgcolorid]);
|
||||
else
|
||||
sprintf (startbuf, "[COLOR=%s]", color_replacement_table[colorid]);
|
||||
|
||||
if ( (*mask & LIBIRC_COLORPARSER_COLOR) != 0 )
|
||||
libirc_colorparser_addorcat (destline, destlen, end);
|
||||
|
||||
*mask |= LIBIRC_COLORPARSER_COLOR;
|
||||
libirc_colorparser_addorcat (destline, destlen, startbuf);
|
||||
}
|
||||
|
||||
|
||||
static void libirc_colorparser_closetags (unsigned int * mask,
|
||||
char ** destline, unsigned int * destlen)
|
||||
{
|
||||
if ( *mask & LIBIRC_COLORPARSER_BOLD )
|
||||
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_BOLD, 0, "[/B]");
|
||||
|
||||
if ( *mask & LIBIRC_COLORPARSER_UNDERLINE )
|
||||
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_UNDERLINE, 0, "[/U]");
|
||||
|
||||
if ( *mask & LIBIRC_COLORPARSER_REVERSE )
|
||||
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_REVERSE, 0, "[/I]");
|
||||
|
||||
if ( *mask & LIBIRC_COLORPARSER_COLOR )
|
||||
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_COLOR, 0, "[/COLOR]");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* IRC to [code] color conversion. Or strip.
|
||||
*/
|
||||
static char * libirc_colorparser_irc2code (const char * source, int strip)
|
||||
{
|
||||
unsigned int mask = 0, destlen = 0;
|
||||
char * destline = 0, *d = 0;
|
||||
const char *p;
|
||||
int current_bg = 0;
|
||||
|
||||
/*
|
||||
* There will be two passes. First pass calculates the total length of
|
||||
* the destination string. The second pass allocates memory for the string,
|
||||
* and fills it.
|
||||
*/
|
||||
while ( destline == 0 ) // destline will be set after the 2nd pass
|
||||
{
|
||||
if ( destlen > 0 )
|
||||
{
|
||||
// This is the 2nd pass; allocate memory.
|
||||
if ( (destline = malloc (destlen)) == 0 )
|
||||
return 0;
|
||||
|
||||
d = destline;
|
||||
}
|
||||
|
||||
for ( p = source; *p; p++ )
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case 0x02: // bold
|
||||
if ( strip )
|
||||
continue;
|
||||
|
||||
libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_BOLD, "[B]", "[/B]");
|
||||
break;
|
||||
|
||||
case 0x1F: // underline
|
||||
if ( strip )
|
||||
continue;
|
||||
|
||||
libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_UNDERLINE, "[U]", "[/U]");
|
||||
break;
|
||||
|
||||
case 0x16: // reverse
|
||||
if ( strip )
|
||||
continue;
|
||||
|
||||
libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_REVERSE, "[I]", "[/I]");
|
||||
break;
|
||||
|
||||
case 0x0F: // reset colors
|
||||
if ( strip )
|
||||
continue;
|
||||
|
||||
libirc_colorparser_closetags (&mask, &d, &destlen);
|
||||
break;
|
||||
|
||||
case 0x03: // set color
|
||||
if ( isdigit (p[1]) )
|
||||
{
|
||||
// Parse
|
||||
int bgcolor = -1, color = p[1] - 0x30;
|
||||
p++;
|
||||
|
||||
if ( isdigit (p[1]) )
|
||||
{
|
||||
color = color * 10 + (p[1] - 0x30);
|
||||
p++;
|
||||
}
|
||||
|
||||
// If there is a comma, search for the following
|
||||
// background color
|
||||
if ( p[1] == ',' && isdigit (p[2]) )
|
||||
{
|
||||
bgcolor = p[2] - 0x30;
|
||||
p += 2;
|
||||
|
||||
if ( isdigit (p[1]) )
|
||||
{
|
||||
bgcolor = bgcolor * 10 + (p[1] - 0x30);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for range
|
||||
if ( color <= LIBIRC_COLORPARSER_MAXCOLORS
|
||||
&& bgcolor <= LIBIRC_COLORPARSER_MAXCOLORS )
|
||||
{
|
||||
if ( strip )
|
||||
continue;
|
||||
|
||||
if ( bgcolor != -1 )
|
||||
current_bg = bgcolor;
|
||||
|
||||
libirc_colorparser_applycolor (&mask, &d, &destlen, color, current_bg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( destline )
|
||||
*d++ = *p;
|
||||
else
|
||||
destlen++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Close all the opened tags
|
||||
libirc_colorparser_closetags (&mask, &d, &destlen);
|
||||
destlen++; // for 0-terminator
|
||||
}
|
||||
|
||||
*d = '\0';
|
||||
return destline;
|
||||
}
|
||||
|
||||
|
||||
static int libirc_colorparser_colorlookup (const char * color)
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; color_replacement_table[i]; i++ )
|
||||
if ( !strcmp (color, color_replacement_table[i]) )
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* [code] to IRC color conversion.
|
||||
*/
|
||||
char * irc_color_convert_to_mirc (const char * source)
|
||||
{
|
||||
unsigned int destlen = 0;
|
||||
char * destline = 0, *d = 0;
|
||||
const char *p1, *p2, *cur;
|
||||
|
||||
/*
|
||||
* There will be two passes. First pass calculates the total length of
|
||||
* the destination string. The second pass allocates memory for the string,
|
||||
* and fills it.
|
||||
*/
|
||||
while ( destline == 0 ) // destline will be set after the 2nd pass
|
||||
{
|
||||
if ( destlen > 0 )
|
||||
{
|
||||
// This is the 2nd pass; allocate memory.
|
||||
if ( (destline = malloc (destlen)) == 0 )
|
||||
return 0;
|
||||
|
||||
d = destline;
|
||||
}
|
||||
|
||||
cur = source;
|
||||
while ( (p1 = strchr (cur, '[')) != 0 )
|
||||
{
|
||||
const char * replacedval = 0;
|
||||
p2 = 0;
|
||||
|
||||
// Check if the closing bracket is available after p1
|
||||
// and the tag length is suitable
|
||||
if ( p1[1] != '\0'
|
||||
&& (p2 = strchr (p1, ']')) != 0
|
||||
&& (p2 - p1) > 1
|
||||
&& (p2 - p1) < 31 )
|
||||
{
|
||||
// Get the tag
|
||||
char tagbuf[32];
|
||||
int taglen = p2 - p1 - 1;
|
||||
|
||||
memcpy (tagbuf, p1 + 1, taglen);
|
||||
tagbuf[taglen] = '\0';
|
||||
|
||||
if ( !strcmp (tagbuf, "/COLOR") )
|
||||
replacedval = "\x0F";
|
||||
else if ( strstr (tagbuf, "COLOR=") == tagbuf )
|
||||
{
|
||||
int color, bgcolor = -2;
|
||||
char * bcol;
|
||||
|
||||
bcol = strchr (tagbuf + 6, '/');
|
||||
|
||||
if ( bcol )
|
||||
{
|
||||
*bcol++ = '\0';
|
||||
bgcolor = libirc_colorparser_colorlookup (bcol);
|
||||
}
|
||||
|
||||
color = libirc_colorparser_colorlookup (tagbuf + 6);
|
||||
|
||||
if ( color != -1 && bgcolor == -2 )
|
||||
{
|
||||
sprintf (tagbuf, "\x03%02d", color);
|
||||
replacedval = tagbuf;
|
||||
}
|
||||
else if ( color != -1 && bgcolor >= 0 )
|
||||
{
|
||||
sprintf (tagbuf, "\x03%02d,%02d", color, bgcolor);
|
||||
replacedval = tagbuf;
|
||||
}
|
||||
}
|
||||
else if ( !strcmp (tagbuf, "B") || !strcmp (tagbuf, "/B") )
|
||||
replacedval = "\x02";
|
||||
else if ( !strcmp (tagbuf, "U") || !strcmp (tagbuf, "/U") )
|
||||
replacedval = "\x1F";
|
||||
else if ( !strcmp (tagbuf, "I") || !strcmp (tagbuf, "/I") )
|
||||
replacedval = "\x16";
|
||||
}
|
||||
|
||||
if ( replacedval )
|
||||
{
|
||||
// add a part before the tag
|
||||
int partlen = p1 - cur;
|
||||
|
||||
if ( destline )
|
||||
{
|
||||
memcpy (d, cur, partlen);
|
||||
d += partlen;
|
||||
}
|
||||
else
|
||||
destlen += partlen;
|
||||
|
||||
// Add the replacement
|
||||
libirc_colorparser_addorcat (&d, &destlen, replacedval);
|
||||
|
||||
// And move the pointer
|
||||
cur = p2 + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// add a whole part before the end tag
|
||||
int partlen;
|
||||
|
||||
if ( !p2 )
|
||||
p2 = cur + strlen(cur);
|
||||
|
||||
partlen = p2 - cur + 1;
|
||||
|
||||
if ( destline )
|
||||
{
|
||||
memcpy (d, cur, partlen);
|
||||
d += partlen;
|
||||
}
|
||||
else
|
||||
destlen += partlen;
|
||||
|
||||
// And move the pointer
|
||||
cur = p2 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the rest of string
|
||||
libirc_colorparser_addorcat (&d, &destlen, cur);
|
||||
destlen++; // for 0-terminator
|
||||
}
|
||||
|
||||
*d = '\0';
|
||||
return destline;
|
||||
}
|
||||
|
||||
|
||||
char * irc_color_strip_from_mirc (const char * message)
|
||||
{
|
||||
return libirc_colorparser_irc2code (message, 1);
|
||||
}
|
||||
|
||||
|
||||
char * irc_color_convert_from_mirc (const char * message)
|
||||
{
|
||||
return libirc_colorparser_irc2code (message, 0);
|
||||
}
|
892
external/IRC/dcc.c
vendored
892
external/IRC/dcc.c
vendored
@ -1,892 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LIBIRC_DCC_CHAT 1
|
||||
#define LIBIRC_DCC_SENDFILE 2
|
||||
#define LIBIRC_DCC_RECVFILE 3
|
||||
|
||||
|
||||
static irc_dcc_session_t * libirc_find_dcc_session (irc_session_t * session, irc_dcc_t dccid, int lock_list)
|
||||
{
|
||||
irc_dcc_session_t * s, *found = 0;
|
||||
|
||||
if ( lock_list )
|
||||
libirc_mutex_lock (&session->mutex_dcc);
|
||||
|
||||
for ( s = session->dcc_sessions; s; s = s->next )
|
||||
{
|
||||
if ( s->id == dccid )
|
||||
{
|
||||
found = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( found == 0 && lock_list )
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
static void libirc_dcc_destroy_nolock (irc_session_t * session, irc_dcc_t dccid)
|
||||
{
|
||||
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 0);
|
||||
|
||||
if ( dcc )
|
||||
{
|
||||
if ( dcc->sock >= 0 )
|
||||
socket_close (&dcc->sock);
|
||||
|
||||
dcc->state = LIBIRC_STATE_REMOVED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void libirc_remove_dcc_session (irc_session_t * session, irc_dcc_session_t * dcc, int lock_list)
|
||||
{
|
||||
if ( dcc->sock >= 0 )
|
||||
socket_close (&dcc->sock);
|
||||
|
||||
if ( dcc->dccsend_file_fp )
|
||||
fclose (dcc->dccsend_file_fp);
|
||||
|
||||
dcc->dccsend_file_fp = 0;
|
||||
|
||||
libirc_mutex_destroy (&dcc->mutex_outbuf);
|
||||
|
||||
if ( lock_list )
|
||||
libirc_mutex_lock (&session->mutex_dcc);
|
||||
|
||||
if ( session->dcc_sessions != dcc )
|
||||
{
|
||||
irc_dcc_session_t * s;
|
||||
for ( s = session->dcc_sessions; s; s = s->next )
|
||||
{
|
||||
if ( s->next == dcc )
|
||||
{
|
||||
s->next = dcc->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
session->dcc_sessions = dcc->next;
|
||||
|
||||
if ( lock_list )
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
|
||||
free (dcc);
|
||||
}
|
||||
|
||||
|
||||
static void libirc_dcc_add_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set, int * maxfd)
|
||||
{
|
||||
irc_dcc_session_t * dcc, *dcc_next;
|
||||
time_t now = time (0);
|
||||
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
|
||||
// Preprocessing DCC list:
|
||||
// - ask DCC send callbacks for data;
|
||||
// - remove unused DCC structures
|
||||
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc_next )
|
||||
{
|
||||
dcc_next = dcc->next;
|
||||
|
||||
// Remove timed-out sessions
|
||||
if ( (dcc->state == LIBIRC_STATE_CONNECTING
|
||||
|| dcc->state == LIBIRC_STATE_INIT
|
||||
|| dcc->state == LIBIRC_STATE_LISTENING)
|
||||
&& now - dcc->timeout > ircsession->dcc_timeout )
|
||||
{
|
||||
// Inform the caller about DCC timeout.
|
||||
// Do not inform when state is LIBIRC_STATE_INIT - session
|
||||
// was initiated from someone else, and callbacks aren't set yet.
|
||||
if ( dcc->state != LIBIRC_STATE_INIT )
|
||||
{
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
|
||||
if ( dcc->cb )
|
||||
(*dcc->cb)(ircsession, dcc->id, LIBIRC_ERR_TIMEOUT, dcc->ctx, 0, 0);
|
||||
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
}
|
||||
|
||||
libirc_remove_dcc_session (ircsession, dcc, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're sending file, and the output buffer is empty, we need
|
||||
* to provide some data.
|
||||
*/
|
||||
if ( dcc->state == LIBIRC_STATE_CONNECTED
|
||||
&& dcc->dccmode == LIBIRC_DCC_SENDFILE
|
||||
&& dcc->dccsend_file_fp
|
||||
&& dcc->outgoing_offset == 0 )
|
||||
{
|
||||
int len = fread (dcc->outgoing_buf, 1, sizeof (dcc->outgoing_buf), dcc->dccsend_file_fp);
|
||||
|
||||
if ( len <= 0 )
|
||||
{
|
||||
int err = (len < 0 ? LIBIRC_ERR_READ : 0);
|
||||
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
libirc_dcc_destroy_nolock (ircsession, dcc->id);
|
||||
}
|
||||
else
|
||||
dcc->outgoing_offset = len;
|
||||
}
|
||||
|
||||
// Clean up unused sessions
|
||||
if ( dcc->state == LIBIRC_STATE_REMOVED )
|
||||
libirc_remove_dcc_session (ircsession, dcc, 0);
|
||||
}
|
||||
|
||||
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next )
|
||||
{
|
||||
switch (dcc->state)
|
||||
{
|
||||
case LIBIRC_STATE_LISTENING:
|
||||
// While listening, only in_set descriptor should be set
|
||||
libirc_add_to_set (dcc->sock, in_set, maxfd);
|
||||
break;
|
||||
|
||||
case LIBIRC_STATE_CONNECTING:
|
||||
// While connection, only out_set descriptor should be set
|
||||
libirc_add_to_set (dcc->sock, out_set, maxfd);
|
||||
break;
|
||||
|
||||
case LIBIRC_STATE_CONNECTED:
|
||||
// Add input descriptor if there is space in input buffer
|
||||
// and it is DCC chat (during DCC send, there is nothing to recv)
|
||||
if ( dcc->incoming_offset < sizeof(dcc->incoming_buf) - 1 )
|
||||
libirc_add_to_set (dcc->sock, in_set, maxfd);
|
||||
|
||||
// Add output descriptor if there is something in output buffer
|
||||
libirc_mutex_lock (&dcc->mutex_outbuf);
|
||||
|
||||
if ( dcc->outgoing_offset > 0 )
|
||||
libirc_add_to_set (dcc->sock, out_set, maxfd);
|
||||
|
||||
libirc_mutex_unlock (&dcc->mutex_outbuf);
|
||||
break;
|
||||
|
||||
case LIBIRC_STATE_CONFIRM_SIZE:
|
||||
/*
|
||||
* If we're receiving file, then WE should confirm the transferred
|
||||
* part (so we have to sent data). But if we're sending the file,
|
||||
* then RECEIVER should confirm the packet, so we have to receive
|
||||
* data.
|
||||
*
|
||||
* We don't need to LOCK_DCC_OUTBUF - during file transfer, buffers
|
||||
* can't change asynchronously.
|
||||
*/
|
||||
if ( dcc->dccmode == LIBIRC_DCC_RECVFILE && dcc->outgoing_offset > 0 )
|
||||
libirc_add_to_set (dcc->sock, out_set, maxfd);
|
||||
|
||||
if ( dcc->dccmode == LIBIRC_DCC_SENDFILE && dcc->incoming_offset < 4 )
|
||||
libirc_add_to_set (dcc->sock, in_set, maxfd);
|
||||
}
|
||||
}
|
||||
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
}
|
||||
|
||||
|
||||
static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set)
|
||||
{
|
||||
irc_dcc_session_t * dcc;
|
||||
|
||||
/*
|
||||
* We need to use such a complex scheme here, because on every callback
|
||||
* a number of DCC sessions could be destroyed.
|
||||
*/
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
|
||||
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next )
|
||||
{
|
||||
if ( dcc->state == LIBIRC_STATE_LISTENING
|
||||
&& FD_ISSET (dcc->sock, in_set) )
|
||||
{
|
||||
socklen_t len = sizeof(dcc->remote_addr);
|
||||
int nsock, err = 0;
|
||||
|
||||
// New connection is available; accept it.
|
||||
if ( socket_accept (&dcc->sock, (socket_t*)&nsock, (struct sockaddr *) &dcc->remote_addr, &len) )
|
||||
err = LIBIRC_ERR_ACCEPT;
|
||||
|
||||
// On success, change the active socket and change the state
|
||||
if ( err == 0 )
|
||||
{
|
||||
// close the listen socket, and replace it by a newly
|
||||
// accepted
|
||||
socket_close (&dcc->sock);
|
||||
dcc->sock = nsock;
|
||||
dcc->state = LIBIRC_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
// If this is DCC chat, inform the caller about accept()
|
||||
// success or failure.
|
||||
// Otherwise (DCC send) there is no reason.
|
||||
if ( dcc->dccmode == LIBIRC_DCC_CHAT )
|
||||
{
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
}
|
||||
|
||||
if ( err )
|
||||
libirc_dcc_destroy_nolock (ircsession, dcc->id);
|
||||
}
|
||||
|
||||
if ( dcc->state == LIBIRC_STATE_CONNECTING
|
||||
&& FD_ISSET (dcc->sock, out_set) )
|
||||
{
|
||||
// Now we have to determine whether the socket is connected
|
||||
// or the connect is failed
|
||||
struct sockaddr_in saddr;
|
||||
socklen_t slen = sizeof(saddr);
|
||||
int err = 0;
|
||||
|
||||
if ( getpeername (dcc->sock, (struct sockaddr*)&saddr, &slen) < 0 )
|
||||
err = LIBIRC_ERR_CONNECT;
|
||||
|
||||
// On success, change the state
|
||||
if ( err == 0 )
|
||||
dcc->state = LIBIRC_STATE_CONNECTED;
|
||||
|
||||
// If this is DCC chat, inform the caller about connect()
|
||||
// success or failure.
|
||||
// Otherwise (DCC send) there is no reason.
|
||||
if ( dcc->dccmode == LIBIRC_DCC_CHAT )
|
||||
{
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
}
|
||||
|
||||
if ( err )
|
||||
libirc_dcc_destroy_nolock (ircsession, dcc->id);
|
||||
}
|
||||
|
||||
if ( dcc->state == LIBIRC_STATE_CONNECTED
|
||||
|| dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
|
||||
{
|
||||
if ( FD_ISSET (dcc->sock, in_set) )
|
||||
{
|
||||
int length, offset = 0, err = 0;
|
||||
|
||||
unsigned int amount = sizeof (dcc->incoming_buf) - dcc->incoming_offset;
|
||||
|
||||
length = socket_recv (&dcc->sock, dcc->incoming_buf + dcc->incoming_offset, amount);
|
||||
|
||||
if ( length < 0 )
|
||||
{
|
||||
err = LIBIRC_ERR_READ;
|
||||
}
|
||||
else if ( length == 0 )
|
||||
{
|
||||
err = LIBIRC_ERR_CLOSED;
|
||||
|
||||
if ( dcc->dccsend_file_fp )
|
||||
{
|
||||
fclose (dcc->dccsend_file_fp);
|
||||
dcc->dccsend_file_fp = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dcc->incoming_offset += length;
|
||||
|
||||
if ( dcc->dccmode != LIBIRC_DCC_CHAT )
|
||||
offset = dcc->incoming_offset;
|
||||
else
|
||||
offset = libirc_findcrorlf (dcc->incoming_buf, dcc->incoming_offset);
|
||||
|
||||
/*
|
||||
* In LIBIRC_STATE_CONFIRM_SIZE state we don't call any
|
||||
* callbacks (except there is an error). We just receive
|
||||
* the data, and compare it with the amount sent.
|
||||
*/
|
||||
if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
|
||||
{
|
||||
if ( dcc->dccmode != LIBIRC_DCC_SENDFILE )
|
||||
abort();
|
||||
|
||||
if ( dcc->incoming_offset == 4 )
|
||||
{
|
||||
// The order is big-endian
|
||||
const unsigned char * bptr = (const unsigned char *) dcc->incoming_buf;
|
||||
unsigned int received_size = (bptr[0] << 24) | (bptr[1] << 16) | (bptr[2] << 8) | bptr[3];
|
||||
|
||||
// Sent size confirmed
|
||||
if ( dcc->file_confirm_offset == received_size )
|
||||
{
|
||||
dcc->state = LIBIRC_STATE_CONNECTED;
|
||||
dcc->incoming_offset = 0;
|
||||
}
|
||||
else
|
||||
err = LIBIRC_ERR_WRITE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If it is DCC_CHAT, we send a 0-terminated string
|
||||
* (which is smaller than offset). Otherwise we send
|
||||
* a full buffer.
|
||||
*/
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
|
||||
if ( dcc->dccmode != LIBIRC_DCC_CHAT )
|
||||
{
|
||||
if ( dcc->dccmode != LIBIRC_DCC_RECVFILE )
|
||||
abort();
|
||||
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, offset);
|
||||
|
||||
/*
|
||||
* If the session is not terminated in callback,
|
||||
* put the sent amount into the sent_packet_size_net_byteorder
|
||||
*/
|
||||
if ( dcc->state != LIBIRC_STATE_REMOVED )
|
||||
{
|
||||
dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
|
||||
dcc->file_confirm_offset += offset;
|
||||
|
||||
// Store as big endian
|
||||
dcc->outgoing_buf[0] = (char) dcc->file_confirm_offset >> 24;
|
||||
dcc->outgoing_buf[1] = (char) dcc->file_confirm_offset >> 16;
|
||||
dcc->outgoing_buf[2] = (char) dcc->file_confirm_offset >> 8;
|
||||
dcc->outgoing_buf[3] = (char) dcc->file_confirm_offset;
|
||||
dcc->outgoing_offset = 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, strlen(dcc->incoming_buf));
|
||||
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
|
||||
if ( dcc->incoming_offset - offset > 0 )
|
||||
memmove (dcc->incoming_buf, dcc->incoming_buf + offset, dcc->incoming_offset - offset);
|
||||
|
||||
dcc->incoming_offset -= offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If error arises somewhere above, we inform the caller
|
||||
* of failure, and destroy this session.
|
||||
*/
|
||||
if ( err )
|
||||
{
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
libirc_dcc_destroy_nolock (ircsession, dcc->id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Session might be closed (with sock = -1) after the in_set
|
||||
* processing, so before out_set processing we should check
|
||||
* for this case
|
||||
*/
|
||||
if ( dcc->state == LIBIRC_STATE_REMOVED )
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Write bit set - we can send() something, and it won't block.
|
||||
*/
|
||||
if ( FD_ISSET (dcc->sock, out_set) )
|
||||
{
|
||||
int length, offset, err = 0;
|
||||
|
||||
/*
|
||||
* Because in some cases outgoing_buf could be changed
|
||||
* asynchronously (by another thread), we should lock
|
||||
* it.
|
||||
*/
|
||||
libirc_mutex_lock (&dcc->mutex_outbuf);
|
||||
|
||||
offset = dcc->outgoing_offset;
|
||||
|
||||
if ( offset > 0 )
|
||||
{
|
||||
length = socket_send (&dcc->sock, dcc->outgoing_buf, offset);
|
||||
|
||||
if ( length < 0 )
|
||||
err = LIBIRC_ERR_WRITE;
|
||||
else if ( length == 0 )
|
||||
err = LIBIRC_ERR_CLOSED;
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If this was DCC_SENDFILE, and we just sent a packet,
|
||||
* change the state to wait for confirmation (and store
|
||||
* sent packet size)
|
||||
*/
|
||||
if ( dcc->state == LIBIRC_STATE_CONNECTED
|
||||
&& dcc->dccmode == LIBIRC_DCC_SENDFILE )
|
||||
{
|
||||
dcc->file_confirm_offset += offset;
|
||||
dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
|
||||
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
libirc_mutex_unlock (&dcc->mutex_outbuf);
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, offset);
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
libirc_mutex_lock (&dcc->mutex_outbuf);
|
||||
}
|
||||
|
||||
if ( dcc->outgoing_offset - length > 0 )
|
||||
memmove (dcc->outgoing_buf, dcc->outgoing_buf + length, dcc->outgoing_offset - length);
|
||||
|
||||
dcc->outgoing_offset -= length;
|
||||
|
||||
/*
|
||||
* If we just sent the confirmation data, change state
|
||||
* back.
|
||||
*/
|
||||
if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE
|
||||
&& dcc->dccmode == LIBIRC_DCC_RECVFILE
|
||||
&& dcc->outgoing_offset == 0 )
|
||||
{
|
||||
/*
|
||||
* If the file is already received, we should inform
|
||||
* the caller, and close the session.
|
||||
*/
|
||||
if ( dcc->received_file_size == dcc->file_confirm_offset )
|
||||
{
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
libirc_mutex_unlock (&dcc->mutex_outbuf);
|
||||
(*dcc->cb)(ircsession, dcc->id, 0, dcc->ctx, 0, 0);
|
||||
libirc_dcc_destroy_nolock (ircsession, dcc->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Continue to receive the file */
|
||||
dcc->state = LIBIRC_STATE_CONNECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libirc_mutex_unlock (&dcc->mutex_outbuf);
|
||||
|
||||
/*
|
||||
* If error arises somewhere above, we inform the caller
|
||||
* of failure, and destroy this session.
|
||||
*/
|
||||
if ( err )
|
||||
{
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
|
||||
libirc_mutex_lock (&ircsession->mutex_dcc);
|
||||
|
||||
libirc_dcc_destroy_nolock (ircsession, dcc->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libirc_mutex_unlock (&ircsession->mutex_dcc);
|
||||
}
|
||||
|
||||
|
||||
static int libirc_new_dcc_session (irc_session_t * session, unsigned long ip, unsigned short port, int dccmode, void * ctx, irc_dcc_session_t ** pdcc)
|
||||
{
|
||||
irc_dcc_session_t * dcc = malloc (sizeof(irc_dcc_session_t));
|
||||
|
||||
if ( !dcc )
|
||||
return LIBIRC_ERR_NOMEM;
|
||||
|
||||
// setup
|
||||
memset (dcc, 0, sizeof(irc_dcc_session_t));
|
||||
|
||||
dcc->dccsend_file_fp = 0;
|
||||
|
||||
if ( libirc_mutex_init (&dcc->mutex_outbuf) )
|
||||
goto cleanup_exit_error;
|
||||
|
||||
if ( socket_create (PF_INET, SOCK_STREAM, &dcc->sock) )
|
||||
goto cleanup_exit_error;
|
||||
|
||||
if ( !ip )
|
||||
{
|
||||
unsigned long arg = 1;
|
||||
|
||||
setsockopt (dcc->sock, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, sizeof(arg));
|
||||
|
||||
#if defined (ENABLE_IPV6)
|
||||
if ( session->flags & SESSIONFL_USES_IPV6 )
|
||||
{
|
||||
struct sockaddr_in6 saddr6;
|
||||
|
||||
memset (&saddr6, 0, sizeof(saddr6));
|
||||
saddr6.sin6_family = AF_INET6;
|
||||
memcpy (&saddr6.sin6_addr, &session->local_addr6, sizeof(session->local_addr6));
|
||||
saddr6.sin6_port = htons (0);
|
||||
|
||||
if ( bind (dcc->sock, (struct sockaddr *) &saddr6, sizeof(saddr6)) < 0 )
|
||||
goto cleanup_exit_error;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
memset (&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = AF_INET;
|
||||
memcpy (&saddr.sin_addr, &session->local_addr, sizeof(session->local_addr));
|
||||
saddr.sin_port = htons (0);
|
||||
|
||||
if ( bind (dcc->sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0 )
|
||||
goto cleanup_exit_error;
|
||||
}
|
||||
|
||||
if ( listen (dcc->sock, 5) < 0 )
|
||||
goto cleanup_exit_error;
|
||||
|
||||
dcc->state = LIBIRC_STATE_LISTENING;
|
||||
}
|
||||
else
|
||||
{
|
||||
// make socket non-blocking, so connect() call won't block
|
||||
if ( socket_make_nonblocking (&dcc->sock) )
|
||||
goto cleanup_exit_error;
|
||||
|
||||
memset (&dcc->remote_addr, 0, sizeof(dcc->remote_addr));
|
||||
dcc->remote_addr.sin_family = AF_INET;
|
||||
dcc->remote_addr.sin_addr.s_addr = htonl (ip); // what idiot came up with idea to send IP address in host-byteorder?
|
||||
dcc->remote_addr.sin_port = htons(port);
|
||||
|
||||
dcc->state = LIBIRC_STATE_INIT;
|
||||
}
|
||||
|
||||
dcc->dccmode = dccmode;
|
||||
dcc->ctx = ctx;
|
||||
time (&dcc->timeout);
|
||||
|
||||
// and store it
|
||||
libirc_mutex_lock (&session->mutex_dcc);
|
||||
|
||||
dcc->id = session->dcc_last_id++;
|
||||
dcc->next = session->dcc_sessions;
|
||||
session->dcc_sessions = dcc;
|
||||
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
|
||||
*pdcc = dcc;
|
||||
return 0;
|
||||
|
||||
cleanup_exit_error:
|
||||
if ( dcc->sock >= 0 )
|
||||
socket_close (&dcc->sock);
|
||||
|
||||
free (dcc);
|
||||
return LIBIRC_ERR_SOCKET;
|
||||
}
|
||||
|
||||
|
||||
int irc_dcc_destroy (irc_session_t * session, irc_dcc_t dccid)
|
||||
{
|
||||
// This function doesn't actually destroy the session; it just changes
|
||||
// its state to "removed" and closes the socket. The memory is actually
|
||||
// freed after the processing loop.
|
||||
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
|
||||
|
||||
if ( !dcc )
|
||||
return 1;
|
||||
|
||||
if ( dcc->sock >= 0 )
|
||||
socket_close (&dcc->sock);
|
||||
|
||||
dcc->state = LIBIRC_STATE_REMOVED;
|
||||
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int irc_dcc_chat (irc_session_t * session, void * ctx, const char * nick, irc_dcc_callback_t callback, irc_dcc_t * dccid)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
socklen_t len = sizeof(saddr);
|
||||
char cmdbuf[128], notbuf[128];
|
||||
irc_dcc_session_t * dcc;
|
||||
int err;
|
||||
|
||||
if ( session->state != LIBIRC_STATE_CONNECTED )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_STATE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = libirc_new_dcc_session (session, 0, 0, LIBIRC_DCC_CHAT, ctx, &dcc);
|
||||
|
||||
if ( err )
|
||||
{
|
||||
session->lasterror = err;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( getsockname (dcc->sock, (struct sockaddr*) &saddr, &len) < 0 )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_SOCKET;
|
||||
libirc_remove_dcc_session (session, dcc, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sprintf (notbuf, "DCC Chat (%s)", inet_ntoa (saddr.sin_addr));
|
||||
sprintf (cmdbuf, "DCC CHAT chat %lu %u", (unsigned long) ntohl (saddr.sin_addr.s_addr), ntohs (saddr.sin_port));
|
||||
|
||||
if ( irc_cmd_notice (session, nick, notbuf)
|
||||
|| irc_cmd_ctcp_request (session, nick, cmdbuf) )
|
||||
{
|
||||
libirc_remove_dcc_session (session, dcc, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*dccid = dcc->id;
|
||||
dcc->cb = callback;
|
||||
dcc->dccmode = LIBIRC_DCC_CHAT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int irc_dcc_msg (irc_session_t * session, irc_dcc_t dccid, const char * text)
|
||||
{
|
||||
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
|
||||
|
||||
if ( !dcc )
|
||||
return 1;
|
||||
|
||||
if ( dcc->dccmode != LIBIRC_DCC_CHAT )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_INVAL;
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( (strlen(text) + 2) >= (sizeof(dcc->outgoing_buf) - dcc->outgoing_offset) )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_NOMEM;
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
libirc_mutex_lock (&dcc->mutex_outbuf);
|
||||
|
||||
strcpy (dcc->outgoing_buf + dcc->outgoing_offset, text);
|
||||
dcc->outgoing_offset += strlen (text);
|
||||
dcc->outgoing_buf[dcc->outgoing_offset++] = 0x0D;
|
||||
dcc->outgoing_buf[dcc->outgoing_offset++] = 0x0A;
|
||||
|
||||
libirc_mutex_unlock (&dcc->mutex_outbuf);
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void libirc_dcc_request (irc_session_t * session, const char * nick, const char * req)
|
||||
{
|
||||
char filenamebuf[256];
|
||||
unsigned long ip, size;
|
||||
unsigned short port;
|
||||
|
||||
if ( sscanf (req, "DCC CHAT chat %lu %hu", &ip, &port) == 2 )
|
||||
{
|
||||
if ( session->callbacks.event_dcc_chat_req )
|
||||
{
|
||||
irc_dcc_session_t * dcc;
|
||||
|
||||
int err = libirc_new_dcc_session (session, ip, port, LIBIRC_DCC_CHAT, 0, &dcc);
|
||||
if ( err )
|
||||
{
|
||||
session->lasterror = err;
|
||||
return;
|
||||
}
|
||||
|
||||
(*session->callbacks.event_dcc_chat_req) (session,
|
||||
nick,
|
||||
inet_ntoa (dcc->remote_addr.sin_addr),
|
||||
dcc->id);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if ( sscanf (req, "DCC SEND %s %lu %hu %lu", filenamebuf, &ip, &port, &size) == 4 )
|
||||
{
|
||||
if ( session->callbacks.event_dcc_send_req )
|
||||
{
|
||||
irc_dcc_session_t * dcc;
|
||||
|
||||
int err = libirc_new_dcc_session (session, ip, port, LIBIRC_DCC_RECVFILE, 0, &dcc);
|
||||
if ( err )
|
||||
{
|
||||
session->lasterror = err;
|
||||
return;
|
||||
}
|
||||
|
||||
(*session->callbacks.event_dcc_send_req) (session,
|
||||
nick,
|
||||
inet_ntoa (dcc->remote_addr.sin_addr),
|
||||
filenamebuf,
|
||||
size,
|
||||
dcc->id);
|
||||
|
||||
dcc->received_file_size = size;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#if defined (ENABLE_DEBUG)
|
||||
fprintf (stderr, "BUG: Unhandled DCC message: %s\n", req);
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int irc_dcc_accept (irc_session_t * session, irc_dcc_t dccid, void * ctx, irc_dcc_callback_t callback)
|
||||
{
|
||||
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
|
||||
|
||||
if ( !dcc )
|
||||
return 1;
|
||||
|
||||
if ( dcc->state != LIBIRC_STATE_INIT )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_STATE;
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dcc->cb = callback;
|
||||
dcc->ctx = ctx;
|
||||
|
||||
// Initiate the connect
|
||||
if ( socket_connect (&dcc->sock, (struct sockaddr *) &dcc->remote_addr, sizeof(dcc->remote_addr)) )
|
||||
{
|
||||
libirc_dcc_destroy_nolock (session, dccid);
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
session->lasterror = LIBIRC_ERR_CONNECT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
dcc->state = LIBIRC_STATE_CONNECTING;
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int irc_dcc_decline (irc_session_t * session, irc_dcc_t dccid)
|
||||
{
|
||||
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
|
||||
|
||||
if ( !dcc )
|
||||
return 1;
|
||||
|
||||
if ( dcc->state != LIBIRC_STATE_INIT )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_STATE;
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
libirc_dcc_destroy_nolock (session, dccid);
|
||||
libirc_mutex_unlock (&session->mutex_dcc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int irc_dcc_sendfile (irc_session_t * session, void * ctx, const char * nick, const char * filename, irc_dcc_callback_t callback, irc_dcc_t * dccid)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
socklen_t len = sizeof(saddr);
|
||||
char cmdbuf[128], notbuf[128];
|
||||
irc_dcc_session_t * dcc;
|
||||
const char * p;
|
||||
int err;
|
||||
long filesize;
|
||||
|
||||
if ( !session || !dccid || !filename || !callback )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_INVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( session->state != LIBIRC_STATE_CONNECTED )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_STATE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( (err = libirc_new_dcc_session (session, 0, 0, LIBIRC_DCC_SENDFILE, ctx, &dcc)) != 0 )
|
||||
{
|
||||
session->lasterror = err;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( (dcc->dccsend_file_fp = fopen (filename, "rb")) == 0 )
|
||||
{
|
||||
libirc_remove_dcc_session (session, dcc, 1);
|
||||
session->lasterror = LIBIRC_ERR_OPENFILE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get file length */
|
||||
if ( fseek (dcc->dccsend_file_fp, 0, SEEK_END)
|
||||
|| (filesize = ftell (dcc->dccsend_file_fp)) == -1
|
||||
|| fseek (dcc->dccsend_file_fp, 0, SEEK_SET) )
|
||||
{
|
||||
libirc_remove_dcc_session (session, dcc, 1);
|
||||
session->lasterror = LIBIRC_ERR_NODCCSEND;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( getsockname (dcc->sock, (struct sockaddr*) &saddr, &len) < 0 )
|
||||
{
|
||||
libirc_remove_dcc_session (session, dcc, 1);
|
||||
session->lasterror = LIBIRC_ERR_SOCKET;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Remove path from the filename
|
||||
if ( (p = strrchr (filename, '\\')) == 0
|
||||
&& (p = strrchr (filename, '/')) == 0 )
|
||||
p = filename;
|
||||
else
|
||||
p++; // skip directory slash
|
||||
|
||||
sprintf (notbuf, "DCC Send %s (%s)", p, inet_ntoa (saddr.sin_addr));
|
||||
sprintf (cmdbuf, "DCC SEND %s %lu %u %ld", p, (unsigned long) ntohl (saddr.sin_addr.s_addr), ntohs (saddr.sin_port), filesize);
|
||||
|
||||
if ( irc_cmd_notice (session, nick, notbuf)
|
||||
|| irc_cmd_ctcp_request (session, nick, cmdbuf) )
|
||||
{
|
||||
libirc_remove_dcc_session (session, dcc, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*dccid = dcc->id;
|
||||
dcc->cb = callback;
|
||||
|
||||
return 0;
|
||||
}
|
54
external/IRC/dcc.h
vendored
54
external/IRC/dcc.h
vendored
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_IRC_DCC_H
|
||||
#define INCLUDE_IRC_DCC_H
|
||||
|
||||
|
||||
/*
|
||||
* This structure keeps the state of a single DCC connection.
|
||||
*/
|
||||
struct irc_dcc_session_s
|
||||
{
|
||||
irc_dcc_session_t * next;
|
||||
|
||||
irc_dcc_t id;
|
||||
void * ctx;
|
||||
socket_t sock; /*!< DCC socket */
|
||||
int dccmode; /*!< Boolean value to differ chat vs send
|
||||
requests. Changes the cb behavior - when
|
||||
it is chat, data is sent by lines with
|
||||
stripped CRLFs. In file mode, the data
|
||||
is sent as-is */
|
||||
int state;
|
||||
time_t timeout;
|
||||
|
||||
FILE * dccsend_file_fp;
|
||||
unsigned int received_file_size;
|
||||
unsigned int file_confirm_offset;
|
||||
|
||||
struct sockaddr_in remote_addr;
|
||||
|
||||
char incoming_buf[LIBIRC_DCC_BUFFER_SIZE];
|
||||
unsigned int incoming_offset;
|
||||
|
||||
char outgoing_buf[LIBIRC_DCC_BUFFER_SIZE];
|
||||
unsigned int outgoing_offset;
|
||||
port_mutex_t mutex_outbuf;
|
||||
|
||||
irc_dcc_callback_t cb;
|
||||
};
|
||||
|
||||
|
||||
#endif /* INCLUDE_IRC_DCC_H */
|
54
external/IRC/errors.c
vendored
54
external/IRC/errors.c
vendored
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
static const char * libirc_strerror[LIBIRC_ERR_MAX] =
|
||||
{
|
||||
"No error",
|
||||
"Invalid argument",
|
||||
"Host not resolved",
|
||||
"Socket error",
|
||||
"Could not connect",
|
||||
"Remote connection closed",
|
||||
"Out of memory",
|
||||
"Could not accept new connection",
|
||||
"Object not found",
|
||||
"Could not DCC send this object",
|
||||
"Read error",
|
||||
"Write error",
|
||||
"Illegal operation for this state",
|
||||
"Timeout error",
|
||||
"Could not open file",
|
||||
"IRC session terminated",
|
||||
"IPv6 not supported",
|
||||
"SSL not supported",
|
||||
"SSL initialization failed",
|
||||
"SSL connection failed",
|
||||
"SSL certificate verify failed",
|
||||
};
|
||||
|
||||
|
||||
int irc_errno (irc_session_t * session)
|
||||
{
|
||||
return session->lasterror;
|
||||
}
|
||||
|
||||
|
||||
const char * irc_strerror (int ircerrno)
|
||||
{
|
||||
if ( ircerrno >= 0 && ircerrno < LIBIRC_ERR_MAX )
|
||||
return libirc_strerror[ircerrno];
|
||||
else
|
||||
return "Invalid irc_errno value";
|
||||
}
|
||||
|
1258
external/IRC/libircclient.c
vendored
1258
external/IRC/libircclient.c
vendored
File diff suppressed because it is too large
Load Diff
36
external/IRC/params.h
vendored
36
external/IRC/params.h
vendored
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_IRC_PARAMS_H
|
||||
#define INCLUDE_IRC_PARAMS_H
|
||||
|
||||
|
||||
#define LIBIRC_VERSION_HIGH 1
|
||||
#define LIBIRC_VERSION_LOW 8
|
||||
|
||||
#define LIBIRC_BUFFER_SIZE 1024
|
||||
#define LIBIRC_DCC_BUFFER_SIZE 1024
|
||||
|
||||
#define LIBIRC_STATE_INIT 0
|
||||
#define LIBIRC_STATE_LISTENING 1
|
||||
#define LIBIRC_STATE_CONNECTING 2
|
||||
#define LIBIRC_STATE_CONNECTED 3
|
||||
#define LIBIRC_STATE_DISCONNECTED 4
|
||||
#define LIBIRC_STATE_CONFIRM_SIZE 5 // Used only by DCC send to confirm the amount of sent data
|
||||
#define LIBIRC_STATE_REMOVED 10 // this state is used only in DCC
|
||||
|
||||
|
||||
#define SSL_PREFIX '#'
|
||||
|
||||
#endif /* INCLUDE_IRC_PARAMS_H */
|
156
external/IRC/portable.c
vendored
156
external/IRC/portable.c
vendored
@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if !defined (_WIN32)
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined (ENABLE_THREADS)
|
||||
#include <pthread.h>
|
||||
typedef pthread_mutex_t port_mutex_t;
|
||||
|
||||
#if !defined (PTHREAD_MUTEX_RECURSIVE) && defined (PTHREAD_MUTEX_RECURSIVE_NP)
|
||||
#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined (ENABLE_THREADS)
|
||||
typedef CRITICAL_SECTION port_mutex_t;
|
||||
#endif
|
||||
|
||||
#define inline
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
|
||||
#if defined (ENABLE_SSL)
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if defined (ENABLE_THREADS)
|
||||
static inline int libirc_mutex_init (port_mutex_t * mutex)
|
||||
{
|
||||
#if defined (_WIN32)
|
||||
InitializeCriticalSection (mutex);
|
||||
return 0;
|
||||
#elif defined (PTHREAD_MUTEX_RECURSIVE)
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
return (pthread_mutexattr_init (&attr)
|
||||
|| pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE)
|
||||
|| pthread_mutex_init (mutex, &attr));
|
||||
#else /* !defined (PTHREAD_MUTEX_RECURSIVE) */
|
||||
|
||||
return pthread_mutex_init (mutex, 0);
|
||||
|
||||
#endif /* defined (_WIN32) */
|
||||
}
|
||||
|
||||
|
||||
static inline void libirc_mutex_destroy (port_mutex_t * mutex)
|
||||
{
|
||||
#if defined (_WIN32)
|
||||
DeleteCriticalSection (mutex);
|
||||
#else
|
||||
pthread_mutex_destroy (mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline void libirc_mutex_lock (port_mutex_t * mutex)
|
||||
{
|
||||
#if defined (_WIN32)
|
||||
EnterCriticalSection (mutex);
|
||||
#else
|
||||
pthread_mutex_lock (mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline void libirc_mutex_unlock (port_mutex_t * mutex)
|
||||
{
|
||||
#if defined (_WIN32)
|
||||
LeaveCriticalSection (mutex);
|
||||
#else
|
||||
pthread_mutex_unlock (mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef void * port_mutex_t;
|
||||
|
||||
static inline int libirc_mutex_init (port_mutex_t * mutex) { return 0; }
|
||||
static inline void libirc_mutex_destroy (port_mutex_t * mutex) {}
|
||||
static inline void libirc_mutex_lock (port_mutex_t * mutex) {}
|
||||
static inline void libirc_mutex_unlock (port_mutex_t * mutex) {}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Stub for WIN32 dll to initialize winsock API
|
||||
*/
|
||||
#if defined (WIN32_DLL)
|
||||
BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
WORD wVersionRequested = MAKEWORD (1, 1);
|
||||
WSADATA wsaData;
|
||||
|
||||
switch(fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
if ( WSAStartup (wVersionRequested, &wsaData) != 0 )
|
||||
return FALSE;
|
||||
|
||||
DisableThreadLibraryCalls (hinstDll);
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
WSACleanup();
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
79
external/IRC/session.h
vendored
79
external/IRC/session.h
vendored
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_IRC_SESSION_H
|
||||
#define INCLUDE_IRC_SESSION_H
|
||||
|
||||
|
||||
#include "params.h"
|
||||
#include "dcc.h"
|
||||
#include "libirc_events.h"
|
||||
|
||||
|
||||
// Session flags
|
||||
#define SESSIONFL_MOTD_RECEIVED (0x00000001)
|
||||
#define SESSIONFL_SSL_CONNECTION (0x00000002)
|
||||
#define SESSIONFL_SSL_WRITE_WANTS_READ (0x00000004)
|
||||
#define SESSIONFL_SSL_READ_WANTS_WRITE (0x00000008)
|
||||
#define SESSIONFL_USES_IPV6 (0x00000010)
|
||||
|
||||
|
||||
|
||||
struct irc_session_s
|
||||
{
|
||||
void * ctx;
|
||||
int dcc_timeout;
|
||||
|
||||
int options;
|
||||
int lasterror;
|
||||
|
||||
char incoming_buf[LIBIRC_BUFFER_SIZE];
|
||||
unsigned int incoming_offset;
|
||||
|
||||
char outgoing_buf[LIBIRC_BUFFER_SIZE];
|
||||
unsigned int outgoing_offset;
|
||||
port_mutex_t mutex_session;
|
||||
|
||||
socket_t sock;
|
||||
int state;
|
||||
int flags;
|
||||
|
||||
char * server;
|
||||
char * server_password;
|
||||
char * realname;
|
||||
char * username;
|
||||
char * nick;
|
||||
char * ctcp_version;
|
||||
|
||||
#if defined( ENABLE_IPV6 )
|
||||
struct in6_addr local_addr6;
|
||||
#endif
|
||||
|
||||
struct in_addr local_addr;
|
||||
irc_dcc_t dcc_last_id;
|
||||
irc_dcc_session_t * dcc_sessions;
|
||||
port_mutex_t mutex_dcc;
|
||||
|
||||
irc_callbacks_t callbacks;
|
||||
|
||||
#if defined (ENABLE_SSL)
|
||||
SSL * ssl;
|
||||
#endif
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* INCLUDE_IRC_SESSION_H */
|
159
external/IRC/sockets.c
vendored
159
external/IRC/sockets.c
vendored
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The sockets interface was moved out to simplify going OpenSSL integration.
|
||||
*/
|
||||
#if !defined (_WIN32)
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define IS_SOCKET_ERROR(a) ((a)<0)
|
||||
typedef int socket_t;
|
||||
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define IS_SOCKET_ERROR(a) ((a)==SOCKET_ERROR)
|
||||
|
||||
#if !defined(EWOULDBLOCK)
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#endif
|
||||
#if !defined(EINPROGRESS)
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#endif
|
||||
#if !defined(EINTR)
|
||||
#define EINTR WSAEINTR
|
||||
#endif
|
||||
#if !defined(EAGAIN)
|
||||
#define EAGAIN EWOULDBLOCK
|
||||
#endif
|
||||
|
||||
typedef SOCKET socket_t;
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
|
||||
static int socket_error()
|
||||
{
|
||||
#if !defined (_WIN32)
|
||||
return errno;
|
||||
#else
|
||||
return WSAGetLastError();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int socket_create (int domain, int type, socket_t * sock)
|
||||
{
|
||||
*sock = socket (domain, type, 0);
|
||||
return IS_SOCKET_ERROR(*sock) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static int socket_make_nonblocking (socket_t * sock)
|
||||
{
|
||||
#if !defined (_WIN32)
|
||||
return fcntl (*sock, F_SETFL, fcntl (*sock, F_GETFL,0 ) | O_NONBLOCK) != 0;
|
||||
#else
|
||||
unsigned long mode = 0;
|
||||
return ioctlsocket (*sock, FIONBIO, &mode) == SOCKET_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int socket_close (socket_t * sock)
|
||||
{
|
||||
#if !defined (_WIN32)
|
||||
close (*sock);
|
||||
#else
|
||||
closesocket (*sock);
|
||||
#endif
|
||||
|
||||
*sock = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int socket_connect (socket_t * sock, const struct sockaddr *saddr, socklen_t len)
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
if ( connect (*sock, saddr, len) < 0 )
|
||||
{
|
||||
if ( socket_error() == EINTR )
|
||||
continue;
|
||||
|
||||
if ( socket_error() != EINPROGRESS && socket_error() != EWOULDBLOCK )
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int socket_accept (socket_t * sock, socket_t * newsock, struct sockaddr *saddr, socklen_t * len)
|
||||
{
|
||||
while ( IS_SOCKET_ERROR(*newsock = accept (*sock, saddr, len)) )
|
||||
{
|
||||
if ( socket_error() == EINTR )
|
||||
continue;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int socket_recv (socket_t * sock, void * buf, size_t len)
|
||||
{
|
||||
int length;
|
||||
|
||||
while ( (length = recv (*sock, buf, len, 0)) < 0 )
|
||||
{
|
||||
int err = socket_error();
|
||||
|
||||
if ( err != EINTR && err != EAGAIN )
|
||||
break;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
static int socket_send (socket_t * sock, const void *buf, size_t len)
|
||||
{
|
||||
int length;
|
||||
|
||||
while ( (length = send (*sock, buf, len, 0)) < 0 )
|
||||
{
|
||||
int err = socket_error();
|
||||
|
||||
if ( err != EINTR && err != EAGAIN )
|
||||
break;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
390
external/IRC/ssl.c
vendored
390
external/IRC/ssl.c
vendored
@ -1,390 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#if defined (ENABLE_SSL)
|
||||
|
||||
// Nonzero if OpenSSL has been initialized
|
||||
static SSL_CTX * ssl_context = 0;
|
||||
|
||||
#if defined (_WIN32)
|
||||
#include <windows.h>
|
||||
// This array will store all of the mutexes available to OpenSSL
|
||||
static CRITICAL_SECTION * mutex_buf = 0;
|
||||
|
||||
// OpenSSL callback to utilize static locks
|
||||
static void cb_openssl_locking_function( int mode, int n, const char * file, int line )
|
||||
{
|
||||
if ( mode & CRYPTO_LOCK)
|
||||
EnterCriticalSection( &mutex_buf[n] );
|
||||
else
|
||||
LeaveCriticalSection( &mutex_buf[n] );
|
||||
}
|
||||
|
||||
// OpenSSL callback to get the thread ID
|
||||
static unsigned long cb_openssl_id_function(void)
|
||||
{
|
||||
return ((unsigned long) GetCurrentThreadId() );
|
||||
}
|
||||
|
||||
static int alloc_mutexes( unsigned int total )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
// Enable thread safety in OpenSSL
|
||||
mutex_buf = (CRITICAL_SECTION*) malloc( total * sizeof(CRITICAL_SECTION) );
|
||||
|
||||
if ( !mutex_buf )
|
||||
return -1;
|
||||
|
||||
for ( i = 0; i < total; i++)
|
||||
InitializeCriticalSection( &(mutex_buf[i]) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
// This array will store all of the mutexes available to OpenSSL
|
||||
static pthread_mutex_t * mutex_buf = 0;
|
||||
|
||||
// OpenSSL callback to utilize static locks
|
||||
static void cb_openssl_locking_function( int mode, int n, const char * file, int line )
|
||||
{
|
||||
(void)file;
|
||||
(void)line;
|
||||
|
||||
if ( mode & CRYPTO_LOCK)
|
||||
pthread_mutex_lock( &mutex_buf[n] );
|
||||
else
|
||||
pthread_mutex_unlock( &mutex_buf[n] );
|
||||
}
|
||||
|
||||
// OpenSSL callback to get the thread ID
|
||||
static unsigned long cb_openssl_id_function()
|
||||
{
|
||||
return ((unsigned long) pthread_self() );
|
||||
}
|
||||
|
||||
static int alloc_mutexes( unsigned int total )
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
// Enable thread safety in OpenSSL
|
||||
mutex_buf = (pthread_mutex_t*) malloc( total * sizeof(pthread_mutex_t) );
|
||||
|
||||
if ( !mutex_buf )
|
||||
return -1;
|
||||
|
||||
for ( i = 0; i < total; i++)
|
||||
pthread_mutex_init( &(mutex_buf[i]), 0 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int ssl_init_context( irc_session_t * session )
|
||||
{
|
||||
// Load the strings and init the library
|
||||
SSL_load_error_strings();
|
||||
|
||||
// Enable thread safety in OpenSSL
|
||||
if ( alloc_mutexes( CRYPTO_num_locks() ) )
|
||||
return LIBIRC_ERR_NOMEM;
|
||||
|
||||
// Register our callbacks
|
||||
CRYPTO_set_id_callback( cb_openssl_id_function );
|
||||
CRYPTO_set_locking_callback( cb_openssl_locking_function );
|
||||
|
||||
// Init it
|
||||
if ( !SSL_library_init() )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
if ( RAND_status() == 0 )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
// Create an SSL context; currently a single context is used for all connections
|
||||
ssl_context = SSL_CTX_new( SSLv23_method() );
|
||||
|
||||
if ( !ssl_context )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
// Disable SSLv2 as it is unsecure
|
||||
if ( (SSL_CTX_set_options( ssl_context, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) == 0 )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
// Enable only strong ciphers
|
||||
if ( SSL_CTX_set_cipher_list( ssl_context, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" ) != 1 )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
// Set the verification
|
||||
if ( session->options & LIBIRC_OPTION_SSL_NO_VERIFY )
|
||||
SSL_CTX_set_verify( ssl_context, SSL_VERIFY_NONE, 0 );
|
||||
else
|
||||
SSL_CTX_set_verify( ssl_context, SSL_VERIFY_PEER, 0 );
|
||||
|
||||
// Disable session caching
|
||||
SSL_CTX_set_session_cache_mode( ssl_context, SSL_SESS_CACHE_OFF );
|
||||
|
||||
// Enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER so we can move the buffer during sending
|
||||
SSL_CTX_set_mode( ssl_context, SSL_CTX_get_mode(ssl_context) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined (_WIN32)
|
||||
#define SSLINIT_LOCK_MUTEX(a) WaitForSingleObject( a, INFINITE )
|
||||
#define SSLINIT_UNLOCK_MUTEX(a) ReleaseMutex( a )
|
||||
#else
|
||||
#define SSLINIT_LOCK_MUTEX(a) pthread_mutex_lock( &a )
|
||||
#define SSLINIT_UNLOCK_MUTEX(a) pthread_mutex_unlock( &a )
|
||||
#endif
|
||||
|
||||
// Initializes the SSL context. Must be called after the socket is created.
|
||||
static int ssl_init( irc_session_t * session )
|
||||
{
|
||||
static int ssl_context_initialized = 0;
|
||||
|
||||
#if defined (_WIN32)
|
||||
static HANDLE initmutex = 0;
|
||||
|
||||
// First time run? Create the mutex
|
||||
if ( initmutex == 0 )
|
||||
{
|
||||
HANDLE m = CreateMutex( 0, FALSE, 0 );
|
||||
|
||||
// Now we check if the mutex has already been created by another thread performing the init concurrently.
|
||||
// If it was, we close our mutex and use the original one. This could be done synchronously by using the
|
||||
// InterlockedCompareExchangePointer function.
|
||||
if ( InterlockedCompareExchangePointer( &m, m, 0 ) != 0 )
|
||||
CloseHandle( m );
|
||||
}
|
||||
#else
|
||||
static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
// This initialization needs to be performed only once. The problem is that it is called from
|
||||
// irc_connect() and this function may be called simultaneously from different threads. So we have
|
||||
// to use mutex on Linux because it allows static mutex initialization. Windows doesn't, so here
|
||||
// we do the sabre dance around it.
|
||||
SSLINIT_LOCK_MUTEX( initmutex );
|
||||
|
||||
if ( ssl_context_initialized == 0 )
|
||||
{
|
||||
int res = ssl_init_context( session );
|
||||
|
||||
if ( res )
|
||||
{
|
||||
SSLINIT_UNLOCK_MUTEX( initmutex );
|
||||
return res;
|
||||
}
|
||||
|
||||
ssl_context_initialized = 1;
|
||||
}
|
||||
|
||||
SSLINIT_UNLOCK_MUTEX( initmutex );
|
||||
|
||||
// Get the SSL context
|
||||
session->ssl = SSL_new( ssl_context );
|
||||
|
||||
if ( !session->ssl )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
// Let OpenSSL use our socket
|
||||
if ( SSL_set_fd( session->ssl, session->sock) != 1 )
|
||||
return LIBIRC_ERR_SSL_INIT_FAILED;
|
||||
|
||||
// Since we're connecting on our own, tell openssl about it
|
||||
SSL_set_connect_state( session->ssl );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ssl_handle_error( irc_session_t * session, int ssl_error )
|
||||
{
|
||||
if ( ERR_GET_LIB(ssl_error) == ERR_LIB_SSL )
|
||||
{
|
||||
if ( ERR_GET_REASON(ssl_error) == SSL_R_CERTIFICATE_VERIFY_FAILED )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_SSL_CERT_VERIFY_FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ERR_GET_REASON(ssl_error) == SSL_R_UNKNOWN_PROTOCOL )
|
||||
{
|
||||
session->lasterror = LIBIRC_ERR_CONNECT_SSL_FAILED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (ENABLE_DEBUG)
|
||||
if ( IS_DEBUG_ENABLED(session) )
|
||||
fprintf (stderr, "[DEBUG] SSL error: %s\n\t(%d, %d)\n",
|
||||
ERR_error_string( ssl_error, NULL), ERR_GET_LIB( ssl_error), ERR_GET_REASON(ssl_error) );
|
||||
#endif
|
||||
}
|
||||
|
||||
static int ssl_recv( irc_session_t * session )
|
||||
{
|
||||
int count;
|
||||
unsigned int amount = (sizeof (session->incoming_buf) - 1) - session->incoming_offset;
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
// Read up to m_bufferLength bytes
|
||||
count = SSL_read( session->ssl, session->incoming_buf + session->incoming_offset, amount );
|
||||
|
||||
if ( count > 0 )
|
||||
return count;
|
||||
else if ( count == 0 )
|
||||
return -1; // remote connection closed
|
||||
else
|
||||
{
|
||||
int ssl_error = SSL_get_error( session->ssl, count );
|
||||
|
||||
// Handle SSL error since not all of them are actually errors
|
||||
switch ( ssl_error )
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
// This is not really an error. We received something, but
|
||||
// OpenSSL gave nothing to us because all it read was
|
||||
// internal data. Repeat the same read.
|
||||
return 0;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
// This is not really an error. We received something, but
|
||||
// now OpenSSL needs to send the data before returning any
|
||||
// data to us (like negotiations). This means we'd need
|
||||
// to wait for WRITE event, but call SSL_read() again.
|
||||
session->flags |= SESSIONFL_SSL_READ_WANTS_WRITE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This is an SSL error, handle it
|
||||
ssl_handle_error( session, ERR_get_error() );
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int ssl_send( irc_session_t * session )
|
||||
{
|
||||
int count;
|
||||
ERR_clear_error();
|
||||
|
||||
count = SSL_write( session->ssl, session->outgoing_buf, session->outgoing_offset );
|
||||
|
||||
if ( count > 0 )
|
||||
return count;
|
||||
else if ( count == 0 )
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
int ssl_error = SSL_get_error( session->ssl, count );
|
||||
|
||||
switch ( ssl_error )
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
// This is not really an error. We sent some internal OpenSSL data,
|
||||
// but now it needs to read more data before it can send anything.
|
||||
// Thus we wait for READ event, but will call SSL_write() again.
|
||||
session->flags |= SESSIONFL_SSL_WRITE_WANTS_READ;
|
||||
return 0;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
// This is not really an error. We sent some data, but now OpenSSL
|
||||
// wants to send some internal data before sending ours.
|
||||
// Repeat the same write.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This is an SSL error, handle it
|
||||
ssl_handle_error( session, ERR_get_error() );
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Handles both SSL and non-SSL reads.
|
||||
// Returns -1 in case there is an error and socket should be closed/connection terminated
|
||||
// Returns 0 in case there is a temporary error and the call should be retried (SSL_WANTS_WRITE case)
|
||||
// Returns a positive number if we actually read something
|
||||
static int session_socket_read( irc_session_t * session )
|
||||
{
|
||||
int length;
|
||||
|
||||
#if defined (ENABLE_SSL)
|
||||
if ( session->ssl )
|
||||
{
|
||||
// Yes, I know this is tricky
|
||||
if ( session->flags & SESSIONFL_SSL_READ_WANTS_WRITE )
|
||||
{
|
||||
session->flags &= ~SESSIONFL_SSL_READ_WANTS_WRITE;
|
||||
ssl_send( session );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ssl_recv( session );
|
||||
}
|
||||
#endif
|
||||
|
||||
length = socket_recv( &session->sock,
|
||||
session->incoming_buf + session->incoming_offset,
|
||||
(sizeof (session->incoming_buf) - 1) - session->incoming_offset );
|
||||
|
||||
// There is no "retry" errors for regular sockets
|
||||
if ( length <= 0 )
|
||||
return -1;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// Handles both SSL and non-SSL writes.
|
||||
// Returns -1 in case there is an error and socket should be closed/connection terminated
|
||||
// Returns 0 in case there is a temporary error and the call should be retried (SSL_WANTS_WRITE case)
|
||||
// Returns a positive number if we actually sent something
|
||||
static int session_socket_write( irc_session_t * session )
|
||||
{
|
||||
int length;
|
||||
|
||||
#if defined (ENABLE_SSL)
|
||||
if ( session->ssl )
|
||||
{
|
||||
// Yep
|
||||
if ( session->flags & SESSIONFL_SSL_WRITE_WANTS_READ )
|
||||
{
|
||||
session->flags &= ~SESSIONFL_SSL_WRITE_WANTS_READ;
|
||||
ssl_recv( session );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ssl_send( session );
|
||||
}
|
||||
#endif
|
||||
|
||||
length = socket_send (&session->sock, session->outgoing_buf, session->outgoing_offset);
|
||||
|
||||
// There is no "retry" errors for regular sockets
|
||||
if ( length <= 0 )
|
||||
return -1;
|
||||
|
||||
return length;
|
||||
}
|
130
external/IRC/utils.c
vendored
130
external/IRC/utils.c
vendored
@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
static void libirc_add_to_set (int fd, fd_set *set, int * maxfd)
|
||||
{
|
||||
FD_SET (fd, set);
|
||||
|
||||
if ( *maxfd < fd )
|
||||
*maxfd = fd;
|
||||
}
|
||||
|
||||
#if defined (ENABLE_DEBUG)
|
||||
static void libirc_dump_data (const char * prefix, const char * buf, unsigned int length)
|
||||
{
|
||||
printf ("%s: ", prefix);
|
||||
for ( ; length > 0; length -- )
|
||||
printf ("%c", *buf++);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Finds a separator (\x0D\x0A), which separates two lines.
|
||||
*/
|
||||
static int libirc_findcrlf (const char * buf, int length)
|
||||
{
|
||||
int offset = 0;
|
||||
for ( ; offset < length; offset++ )
|
||||
{
|
||||
if ( buf[offset] == 0x0D && offset < length - 1 && buf[offset+1] == 0x0A )
|
||||
return offset;
|
||||
if ( buf[offset] == 0x0A)
|
||||
return offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int libirc_findcrlf_offset(const char *buf, int offset, const int length)
|
||||
{
|
||||
for(; offset < length; offset++)
|
||||
{
|
||||
if(buf[offset] != 0x0D && buf[offset] != 0x0A)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int libirc_findcrorlf (char * buf, int length)
|
||||
{
|
||||
int offset = 0;
|
||||
for ( ; offset < length; offset++ )
|
||||
{
|
||||
if ( buf[offset] == 0x0D || buf[offset] == 0x0A )
|
||||
{
|
||||
buf[offset++] = '\0';
|
||||
|
||||
if ( offset < (length - 1)
|
||||
&& (buf[offset] == 0x0D || buf[offset] == 0x0A) )
|
||||
offset++;
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void libirc_event_ctcp_internal (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
|
||||
{
|
||||
(void)event;
|
||||
(void)count;
|
||||
|
||||
if ( origin )
|
||||
{
|
||||
char nickbuf[128], textbuf[256];
|
||||
irc_target_get_nick (origin, nickbuf, sizeof(nickbuf));
|
||||
|
||||
if ( strstr (params[0], "PING") == params[0] )
|
||||
irc_cmd_ctcp_reply (session, nickbuf, params[0]);
|
||||
else if ( !strcmp (params[0], "VERSION") )
|
||||
{
|
||||
if ( !session->ctcp_version )
|
||||
{
|
||||
unsigned int high, low;
|
||||
irc_get_version (&high, &low);
|
||||
|
||||
snprintf (textbuf, sizeof (textbuf), "VERSION libircclient by Georgy Yunaev ver.%d.%d", high, low);
|
||||
}
|
||||
else
|
||||
snprintf (textbuf, sizeof (textbuf), "VERSION %s", session->ctcp_version);
|
||||
|
||||
irc_cmd_ctcp_reply (session, nickbuf, textbuf);
|
||||
}
|
||||
else if ( !strcmp (params[0], "FINGER") )
|
||||
{
|
||||
sprintf (textbuf, "FINGER %s (%s) Idle 0 seconds",
|
||||
session->username ? session->username : "nobody",
|
||||
session->realname ? session->realname : "noname");
|
||||
|
||||
irc_cmd_ctcp_reply (session, nickbuf, textbuf);
|
||||
}
|
||||
else if ( !strcmp (params[0], "TIME") )
|
||||
{
|
||||
time_t now = time(0);
|
||||
|
||||
#if defined (ENABLE_THREADS) && defined (HAVE_LOCALTIME_R)
|
||||
struct tm tmtmp, *ltime = localtime_r (&now, &tmtmp);
|
||||
#else
|
||||
struct tm * ltime = localtime (&now);
|
||||
#endif
|
||||
strftime (textbuf, sizeof(textbuf), "%a %b %d %H:%M:%S %Z %Y", ltime);
|
||||
irc_cmd_ctcp_reply (session, nickbuf, textbuf);
|
||||
}
|
||||
}
|
||||
}
|
21
external/PUGIXML/license.txt
vendored
21
external/PUGIXML/license.txt
vendored
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2006-2014 Arseny Kapoulkine
|
||||
|
||||
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.
|
12450
external/PUGIXML/pugixml.cpp
vendored
12450
external/PUGIXML/pugixml.cpp
vendored
File diff suppressed because it is too large
Load Diff
57
external/RapidJSON/license.txt
vendored
57
external/RapidJSON/license.txt
vendored
@ -1,57 +0,0 @@
|
||||
Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
|
||||
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
|
||||
If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License.
|
||||
If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license.
|
||||
A copy of the MIT License is included in this file.
|
||||
|
||||
Other dependencies and licenses:
|
||||
|
||||
Open Source Software Licensed Under the BSD License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
The msinttypes r29
|
||||
Copyright (c) 2006-2013 Alexander Chemeris
|
||||
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 copyright holder 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 REGENTS 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 REGENTS AND 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.
|
||||
|
||||
Open Source Software Licensed Under the JSON License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
json.org
|
||||
Copyright (c) 2002 JSON.org
|
||||
All Rights Reserved.
|
||||
|
||||
JSON_checker
|
||||
Copyright (c) 2002 JSON.org
|
||||
All Rights Reserved.
|
||||
|
||||
|
||||
Terms of the JSON License:
|
||||
---------------------------------------------------
|
||||
|
||||
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 shall be used for Good, not Evil.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Terms of the MIT License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
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.
|
15564
external/SQLite/sqlite3.c
vendored
15564
external/SQLite/sqlite3.c
vendored
File diff suppressed because it is too large
Load Diff
539
external/SimpleINI/ConvertUTF.c
vendored
539
external/SimpleINI/ConvertUTF.c
vendored
@ -1,539 +0,0 @@
|
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
*
|
||||
* Disclaimer
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
|
||||
Author: Mark E. Davis, 1994.
|
||||
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||
Sept 2001: fixed const & error conditions per
|
||||
mods suggested by S. Parent & A. Lillich.
|
||||
June 2002: Tim Dodd added detection and handling of incomplete
|
||||
source sequences, enhanced error detection, added casts
|
||||
to eliminate compiler warnings.
|
||||
July 2003: slight mods to back out aggressive FFFE detection.
|
||||
Jan 2004: updated switches in from-UTF8 conversions.
|
||||
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
|
||||
|
||||
See the header file "ConvertUTF.h" for complete documentation.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include "ConvertUTF.h"
|
||||
#ifdef CVTUTF_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
static const int halfShift = 10; /* used for shifting by 10 bits */
|
||||
|
||||
static const UTF32 halfBase = 0x0010000UL;
|
||||
static const UTF32 halfMask = 0x3FFUL;
|
||||
|
||||
#define UNI_SUR_HIGH_START (UTF32)0xD800
|
||||
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
|
||||
#define UNI_SUR_LOW_START (UTF32)0xDC00
|
||||
#define UNI_SUR_LOW_END (UTF32)0xDFFF
|
||||
#define false 0
|
||||
#define true 1
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF32toUTF16 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF32* source = *sourceStart;
|
||||
UTF16* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
if (target >= targetEnd) {
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch = *source++;
|
||||
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||
/* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = (UTF16)ch; /* normal case */
|
||||
}
|
||||
} else if (ch > UNI_MAX_LEGAL_UTF32) {
|
||||
if (flags == strictConversion) {
|
||||
result = sourceIllegal;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||
if (target + 1 >= targetEnd) {
|
||||
--source; /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch -= halfBase;
|
||||
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF16toUTF32 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF16* source = *sourceStart;
|
||||
UTF32* target = *targetStart;
|
||||
UTF32 ch, ch2;
|
||||
while (source < sourceEnd) {
|
||||
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||
ch = *source++;
|
||||
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
|
||||
/* If the 16 bits following the high surrogate are in the source buffer... */
|
||||
if (source < sourceEnd) {
|
||||
ch2 = *source;
|
||||
/* If it's a low surrogate, convert to UTF32. */
|
||||
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||
++source;
|
||||
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
} else { /* We don't have the 16 bits following the high surrogate. */
|
||||
--source; /* return to the high surrogate */
|
||||
result = sourceExhausted;
|
||||
break;
|
||||
}
|
||||
} else if (flags == strictConversion) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target >= targetEnd) {
|
||||
source = oldSource; /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
*target++ = ch;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
#ifdef CVTUTF_DEBUG
|
||||
if (result == sourceIllegal) {
|
||||
fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
|
||||
fflush(stderr);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Index into the table below with the first byte of a UTF-8 sequence to
|
||||
* get the number of trailing bytes that are supposed to follow it.
|
||||
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
|
||||
* left as-is for anyone who may want to do such conversion, which was
|
||||
* allowed in earlier algorithms.
|
||||
*/
|
||||
static const char trailingBytesForUTF8[256] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||
};
|
||||
|
||||
/*
|
||||
* Magic values subtracted from a buffer value during UTF8 conversion.
|
||||
* This table contains as many values as there might be trailing bytes
|
||||
* in a UTF-8 sequence.
|
||||
*/
|
||||
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
|
||||
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
|
||||
|
||||
/*
|
||||
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
|
||||
* into the first byte, depending on how many bytes follow. There are
|
||||
* as many entries in this table as there are UTF-8 sequence types.
|
||||
* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
|
||||
* for *legal* UTF-8 will be 4 or fewer bytes total.
|
||||
*/
|
||||
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* The interface converts a whole buffer to avoid function-call overhead.
|
||||
* Constants have been gathered. Loops & conditionals have been removed as
|
||||
* much as possible for efficiency, in favor of drop-through switches.
|
||||
* (See "Note A" at the bottom of the file for equivalent code.)
|
||||
* If your compiler supports it, the "isLegalUTF8" call can be turned
|
||||
* into an inline function.
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF16toUTF8 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF16* source = *sourceStart;
|
||||
UTF8* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
unsigned short bytesToWrite = 0;
|
||||
const UTF32 byteMask = 0xBF;
|
||||
const UTF32 byteMark = 0x80;
|
||||
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||
ch = *source++;
|
||||
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
|
||||
/* If the 16 bits following the high surrogate are in the source buffer... */
|
||||
if (source < sourceEnd) {
|
||||
UTF32 ch2 = *source;
|
||||
/* If it's a low surrogate, convert to UTF32. */
|
||||
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||
++source;
|
||||
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
} else { /* We don't have the 16 bits following the high surrogate. */
|
||||
--source; /* return to the high surrogate */
|
||||
result = sourceExhausted;
|
||||
break;
|
||||
}
|
||||
} else if (flags == strictConversion) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Figure out how many bytes the result will require */
|
||||
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||
} else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
|
||||
} else { bytesToWrite = 3;
|
||||
ch = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
|
||||
target += bytesToWrite;
|
||||
if (target > targetEnd) {
|
||||
source = oldSource; /* Back up source pointer! */
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
|
||||
}
|
||||
target += bytesToWrite;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
|
||||
* This must be called with the length pre-determined by the first byte.
|
||||
* If not calling this from ConvertUTF8to*, then the length can be set by:
|
||||
* length = trailingBytesForUTF8[*source]+1;
|
||||
* and the sequence is illegal right away if there aren't that many bytes
|
||||
* available.
|
||||
* If presented with a length > 4, this returns false. The Unicode
|
||||
* definition of UTF-8 goes up to 4-byte sequences.
|
||||
*/
|
||||
|
||||
static Boolean isLegalUTF8(const UTF8 *source, int length) {
|
||||
UTF8 a;
|
||||
const UTF8 *srcptr = source+length;
|
||||
switch (length) {
|
||||
default: return false;
|
||||
/* Everything else falls through when "true"... */
|
||||
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
case 2: if ((a = (*--srcptr)) > 0xBF) return false;
|
||||
|
||||
switch (*source) {
|
||||
/* no fall-through in this inner switch */
|
||||
case 0xE0: if (a < 0xA0) return false; break;
|
||||
case 0xED: if (a > 0x9F) return false; break;
|
||||
case 0xF0: if (a < 0x90) return false; break;
|
||||
case 0xF4: if (a > 0x8F) return false; break;
|
||||
default: if (a < 0x80) return false;
|
||||
}
|
||||
|
||||
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
|
||||
}
|
||||
if (*source > 0xF4) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Exported function to return whether a UTF-8 sequence is legal or not.
|
||||
* This is not used here; it's just exported.
|
||||
*/
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
|
||||
int length = trailingBytesForUTF8[*source]+1;
|
||||
if (source+length > sourceEnd) {
|
||||
return false;
|
||||
}
|
||||
return isLegalUTF8(source, length);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF8* source = *sourceStart;
|
||||
UTF16* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch = 0;
|
||||
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||
if (source + extraBytesToRead >= sourceEnd) {
|
||||
result = sourceExhausted; break;
|
||||
}
|
||||
/* Do this check whether lenient or strict */
|
||||
if (! isLegalUTF8(source, extraBytesToRead+1)) {
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
||||
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
||||
case 3: ch += *source++; ch <<= 6;
|
||||
case 2: ch += *source++; ch <<= 6;
|
||||
case 1: ch += *source++; ch <<= 6;
|
||||
case 0: ch += *source++;
|
||||
}
|
||||
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||
|
||||
if (target >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = (UTF16)ch; /* normal case */
|
||||
}
|
||||
} else if (ch > UNI_MAX_UTF16) {
|
||||
if (flags == strictConversion) {
|
||||
result = sourceIllegal;
|
||||
source -= (extraBytesToRead+1); /* return to the start */
|
||||
break; /* Bail out; shouldn't continue */
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||
if (target + 1 >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch -= halfBase;
|
||||
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF32toUTF8 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF32* source = *sourceStart;
|
||||
UTF8* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
unsigned short bytesToWrite = 0;
|
||||
const UTF32 byteMask = 0xBF;
|
||||
const UTF32 byteMark = 0x80;
|
||||
ch = *source++;
|
||||
if (flags == strictConversion ) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Figure out how many bytes the result will require. Turn any
|
||||
* illegally large UTF32 things (> Plane 17) into replacement chars.
|
||||
*/
|
||||
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||
} else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
|
||||
} else { bytesToWrite = 3;
|
||||
ch = UNI_REPLACEMENT_CHAR;
|
||||
result = sourceIllegal;
|
||||
}
|
||||
|
||||
target += bytesToWrite;
|
||||
if (target > targetEnd) {
|
||||
--source; /* Back up source pointer! */
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
|
||||
}
|
||||
target += bytesToWrite;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF8toUTF32 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF8* source = *sourceStart;
|
||||
UTF32* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch = 0;
|
||||
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||
if (source + extraBytesToRead >= sourceEnd) {
|
||||
result = sourceExhausted; break;
|
||||
}
|
||||
/* Do this check whether lenient or strict */
|
||||
if (! isLegalUTF8(source, extraBytesToRead+1)) {
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
case 5: ch += *source++; ch <<= 6;
|
||||
case 4: ch += *source++; ch <<= 6;
|
||||
case 3: ch += *source++; ch <<= 6;
|
||||
case 2: ch += *source++; ch <<= 6;
|
||||
case 1: ch += *source++; ch <<= 6;
|
||||
case 0: ch += *source++;
|
||||
}
|
||||
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||
|
||||
if (target >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up the source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
if (ch <= UNI_MAX_LEGAL_UTF32) {
|
||||
/*
|
||||
* UTF-16 surrogate values are illegal in UTF-32, and anything
|
||||
* over Plane 17 (> 0x10FFFF) is illegal.
|
||||
*/
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = ch;
|
||||
}
|
||||
} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
|
||||
result = sourceIllegal;
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Note A.
|
||||
The fall-through switches in UTF-8 reading code save a
|
||||
temp variable, some decrements & conditionals. The switches
|
||||
are equivalent to the following loop:
|
||||
{
|
||||
int tmpBytesToRead = extraBytesToRead+1;
|
||||
do {
|
||||
ch += *source++;
|
||||
--tmpBytesToRead;
|
||||
if (tmpBytesToRead) ch <<= 6;
|
||||
} while (tmpBytesToRead > 0);
|
||||
}
|
||||
In UTF-8 writing code, the switches on "bytesToWrite" are
|
||||
similarly unrolled loops.
|
||||
|
||||
--------------------------------------------------------------------- */
|
150
external/SimpleINI/README.md
vendored
150
external/SimpleINI/README.md
vendored
@ -1,150 +0,0 @@
|
||||
simpleini
|
||||
=========
|
||||
|
||||
A cross-platform library that provides a simple API to read and write INI-style configuration files. It supports data files in ASCII, MBCS and Unicode. It is designed explicitly to be portable to any platform and has been tested on Windows, WinCE and Linux. Released as open-source and free using the MIT licence.
|
||||
|
||||
# Feature Summary
|
||||
|
||||
- MIT Licence allows free use in all software (including GPL and commercial)
|
||||
- multi-platform (Windows 95/98/ME/NT/2K/XP/2003, Windows CE, Linux, Unix)
|
||||
- loading and saving of INI-style configuration files
|
||||
- configuration files can have any newline format on all platforms
|
||||
- liberal acceptance of file format
|
||||
* key/values with no section
|
||||
* removal of whitespace around sections, keys and values
|
||||
- support for multi-line values (values with embedded newline characters)
|
||||
- optional support for multiple keys with the same name
|
||||
- optional case-insensitive sections and keys (for ASCII characters only)
|
||||
- saves files with sections and keys in the same order as they were loaded
|
||||
- preserves comments on the file, section and keys where possible.
|
||||
- supports both char or wchar_t programming interfaces
|
||||
- supports both MBCS (system locale) and UTF-8 file encodings
|
||||
- system locale does not need to be UTF-8 on Linux/Unix to load UTF-8 file
|
||||
- support for non-ASCII characters in section, keys, values and comments
|
||||
- support for non-standard character types or file encodings via user-written converter classes
|
||||
- support for adding/modifying values programmatically
|
||||
- compiles cleanly in the following compilers:
|
||||
* Windows/VC6 (warning level 3)
|
||||
* Windows/VC.NET 2003 (warning level 4)
|
||||
* Windows/VC 2005 (warning level 4)
|
||||
* Linux/gcc (-Wall)
|
||||
* Windows/MinGW GCC
|
||||
|
||||
# Documentation
|
||||
|
||||
Full documentation of the interface is available in doxygen format.
|
||||
|
||||
# Examples
|
||||
|
||||
These snippets are included with the distribution in the file snippets.cpp.
|
||||
|
||||
### SIMPLE USAGE
|
||||
|
||||
```c++
|
||||
CSimpleIniA ini;
|
||||
ini.SetUnicode();
|
||||
ini.LoadFile("myfile.ini");
|
||||
const char * pVal = ini.GetValue("section", "key", "default");
|
||||
ini.SetValue("section", "key", "newvalue");
|
||||
```
|
||||
|
||||
### LOADING DATA
|
||||
|
||||
```c++
|
||||
// load from a data file
|
||||
CSimpleIniA ini(a_bIsUtf8, a_bUseMultiKey, a_bUseMultiLine);
|
||||
SI_Error rc = ini.LoadFile(a_pszFile);
|
||||
if (rc < 0) return false;
|
||||
|
||||
// load from a string
|
||||
std::string strData;
|
||||
rc = ini.LoadData(strData.c_str(), strData.size());
|
||||
if (rc < 0) return false;
|
||||
```
|
||||
|
||||
### GETTING SECTIONS AND KEYS
|
||||
|
||||
```c++
|
||||
// get all sections
|
||||
CSimpleIniA::TNamesDepend sections;
|
||||
ini.GetAllSections(sections);
|
||||
|
||||
// get all keys in a section
|
||||
CSimpleIniA::TNamesDepend keys;
|
||||
ini.GetAllKeys("section-name", keys);
|
||||
```
|
||||
|
||||
### GETTING VALUES
|
||||
|
||||
```c++
|
||||
// get the value of a key
|
||||
const char * pszValue = ini.GetValue("section-name",
|
||||
"key-name", NULL /*default*/);
|
||||
|
||||
// get the value of a key which may have multiple
|
||||
// values. If bHasMultipleValues is true, then just
|
||||
// one value has been returned
|
||||
bool bHasMultipleValues;
|
||||
pszValue = ini.GetValue("section-name", "key-name",
|
||||
NULL /*default*/, &bHasMultipleValues);
|
||||
|
||||
// get all values of a key with multiple values
|
||||
CSimpleIniA::TNamesDepend values;
|
||||
ini.GetAllValues("section-name", "key-name", values);
|
||||
|
||||
// sort the values into the original load order
|
||||
values.sort(CSimpleIniA::Entry::LoadOrder());
|
||||
|
||||
// output all of the items
|
||||
CSimpleIniA::TNamesDepend::const_iterator i;
|
||||
for (i = values.begin(); i != values.end(); ++i) {
|
||||
printf("key-name = '%s'\n", i->pItem);
|
||||
}
|
||||
```
|
||||
|
||||
### MODIFYING DATA
|
||||
|
||||
```c++
|
||||
// adding a new section
|
||||
rc = ini.SetValue("new-section", NULL, NULL);
|
||||
if (rc < 0) return false;
|
||||
printf("section: %s\n", rc == SI_INSERTED ?
|
||||
"inserted" : "updated");
|
||||
|
||||
// adding a new key ("new-section" will be added
|
||||
// automatically if it doesn't already exist)
|
||||
rc = ini.SetValue("new-section", "new-key", "value");
|
||||
if (rc < 0) return false;
|
||||
printf("key: %s\n", rc == SI_INSERTED ?
|
||||
"inserted" : "updated");
|
||||
|
||||
// changing the value of a key
|
||||
rc = ini.SetValue("section", "key", "updated-value");
|
||||
if (rc < 0) return false;
|
||||
printf("key: %s\n", rc == SI_INSERTED ?
|
||||
"inserted" : "updated");
|
||||
```
|
||||
|
||||
### DELETING DATA
|
||||
|
||||
```c++
|
||||
// deleting a key from a section. Optionally the entire
|
||||
// section may be deleted if it is now empty.
|
||||
ini.Delete("section-name", "key-name",
|
||||
true /*delete the section if empty*/);
|
||||
|
||||
// deleting an entire section and all keys in it
|
||||
ini.Delete("section-name", NULL);
|
||||
```
|
||||
|
||||
### SAVING DATA
|
||||
|
||||
```c++
|
||||
// save the data to a string
|
||||
rc = ini.Save(strData);
|
||||
if (rc < 0) return false;
|
||||
|
||||
// save the data back to the file
|
||||
rc = ini.SaveFile(a_pszFile);
|
||||
if (rc < 0) return false;
|
||||
```
|
74
external/Squirrel/sqapi.cpp
vendored
74
external/Squirrel/sqapi.cpp
vendored
@ -13,7 +13,7 @@
|
||||
#include "sqfuncstate.h"
|
||||
#include "sqclass.h"
|
||||
|
||||
bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPtr **o)
|
||||
static bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPtr **o)
|
||||
{
|
||||
*o = &stack_get(v,idx);
|
||||
if(type(**o) != type){
|
||||
@ -34,7 +34,8 @@ bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPt
|
||||
|
||||
SQInteger sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type)
|
||||
{
|
||||
scsprintf(_ss(v)->GetScratchPad(100), 100 *sizeof(SQChar), _SC("unexpected type %s"), IdType2Name(type));
|
||||
SQUnsignedInteger buf_size = 100 *sizeof(SQChar);
|
||||
scsprintf(_ss(v)->GetScratchPad(buf_size), buf_size, _SC("unexpected type %s"), IdType2Name(type));
|
||||
return sq_throwerror(v, _ss(v)->GetScratchPad(-1));
|
||||
}
|
||||
|
||||
@ -179,6 +180,12 @@ SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po)
|
||||
#endif
|
||||
}
|
||||
|
||||
SQUnsignedInteger sq_getvmrefcount(HSQUIRRELVM v, const HSQOBJECT *po)
|
||||
{
|
||||
if (!ISREFCOUNTED(type(*po))) return 0;
|
||||
return po->_unVal.pRefCounted->_uiRef;
|
||||
}
|
||||
|
||||
const SQChar *sq_objtostring(const HSQOBJECT *o)
|
||||
{
|
||||
if(sq_type(*o) == OT_STRING) {
|
||||
@ -251,6 +258,11 @@ void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p)
|
||||
v->Push(p);
|
||||
}
|
||||
|
||||
void sq_pushthread(HSQUIRRELVM v, HSQUIRRELVM thread)
|
||||
{
|
||||
v->Push(thread);
|
||||
}
|
||||
|
||||
SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size)
|
||||
{
|
||||
SQUserData *ud = SQUserData::Create(_ss(v), size + SQ_ALIGNMENT);
|
||||
@ -443,6 +455,7 @@ SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx)
|
||||
return sq_throwerror(v,_SC("the target is not a closure"));
|
||||
SQObjectPtr &env = stack_get(v,-1);
|
||||
if(!sq_istable(env) &&
|
||||
!sq_isarray(env) &&
|
||||
!sq_isclass(env) &&
|
||||
!sq_isinstance(env))
|
||||
return sq_throwerror(v,_SC("invalid environment"));
|
||||
@ -880,29 +893,30 @@ SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx)
|
||||
SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx)
|
||||
{
|
||||
SQObjectPtr &self = stack_get(v, idx);
|
||||
if(type(v->GetUp(-2)) == OT_NULL) {
|
||||
SQObjectPtr &key = v->GetUp(-2);
|
||||
if(type(key) == OT_NULL) {
|
||||
v->Pop(2);
|
||||
return sq_throwerror(v, _SC("null key"));
|
||||
}
|
||||
switch(type(self)) {
|
||||
case OT_TABLE:
|
||||
_table(self)->NewSlot(v->GetUp(-2), v->GetUp(-1));
|
||||
_table(self)->NewSlot(key, v->GetUp(-1));
|
||||
v->Pop(2);
|
||||
return SQ_OK;
|
||||
break;
|
||||
case OT_CLASS:
|
||||
_class(self)->NewSlot(_ss(v), v->GetUp(-2), v->GetUp(-1),false);
|
||||
_class(self)->NewSlot(_ss(v), key, v->GetUp(-1),false);
|
||||
v->Pop(2);
|
||||
return SQ_OK;
|
||||
break;
|
||||
case OT_INSTANCE:
|
||||
if(_instance(self)->Set(v->GetUp(-2), v->GetUp(-1))) {
|
||||
if(_instance(self)->Set(key, v->GetUp(-1))) {
|
||||
v->Pop(2);
|
||||
return SQ_OK;
|
||||
}
|
||||
break;
|
||||
case OT_ARRAY:
|
||||
if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) {
|
||||
if(v->Set(self, key, v->GetUp(-1),false)) {
|
||||
v->Pop(2);
|
||||
return SQ_OK;
|
||||
}
|
||||
@ -918,8 +932,9 @@ SQRESULT sq_newmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic)
|
||||
{
|
||||
SQObjectPtr &self = stack_get(v, idx);
|
||||
if(type(self) != OT_CLASS) return sq_throwerror(v, _SC("new member only works with classes"));
|
||||
if(type(v->GetUp(-3)) == OT_NULL) return sq_throwerror(v, _SC("null key"));
|
||||
if(!v->NewSlotA(self,v->GetUp(-3),v->GetUp(-2),v->GetUp(-1),bstatic?true:false,false))
|
||||
SQObjectPtr &key = v->GetUp(-3);
|
||||
if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null key"));
|
||||
if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,false))
|
||||
return SQ_ERROR;
|
||||
return SQ_OK;
|
||||
}
|
||||
@ -928,8 +943,9 @@ SQRESULT sq_rawnewmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic)
|
||||
{
|
||||
SQObjectPtr &self = stack_get(v, idx);
|
||||
if(type(self) != OT_CLASS) return sq_throwerror(v, _SC("new member only works with classes"));
|
||||
if(type(v->GetUp(-3)) == OT_NULL) return sq_throwerror(v, _SC("null key"));
|
||||
if(!v->NewSlotA(self,v->GetUp(-3),v->GetUp(-2),v->GetUp(-1),bstatic?true:false,true))
|
||||
SQObjectPtr &key = v->GetUp(-3);
|
||||
if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null key"));
|
||||
if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,true))
|
||||
return SQ_ERROR;
|
||||
return SQ_OK;
|
||||
}
|
||||
@ -999,7 +1015,8 @@ SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx)
|
||||
SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx)
|
||||
{
|
||||
SQObjectPtr &self=stack_get(v,idx);
|
||||
if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,DONT_FALL_BACK))
|
||||
SQObjectPtr &obj = v->GetUp(-1);
|
||||
if(v->Get(self,obj,obj,false,DONT_FALL_BACK))
|
||||
return SQ_OK;
|
||||
v->Pop();
|
||||
return SQ_ERROR;
|
||||
@ -1008,23 +1025,23 @@ SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx)
|
||||
SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx)
|
||||
{
|
||||
SQObjectPtr &self=stack_get(v,idx);
|
||||
SQObjectPtr &obj = v->GetUp(-1);
|
||||
switch(type(self)) {
|
||||
case OT_TABLE:
|
||||
if(_table(self)->Get(v->GetUp(-1),v->GetUp(-1)))
|
||||
if(_table(self)->Get(obj,obj))
|
||||
return SQ_OK;
|
||||
break;
|
||||
case OT_CLASS:
|
||||
if(_class(self)->Get(v->GetUp(-1),v->GetUp(-1)))
|
||||
if(_class(self)->Get(obj,obj))
|
||||
return SQ_OK;
|
||||
break;
|
||||
case OT_INSTANCE:
|
||||
if(_instance(self)->Get(v->GetUp(-1),v->GetUp(-1)))
|
||||
if(_instance(self)->Get(obj,obj))
|
||||
return SQ_OK;
|
||||
break;
|
||||
case OT_ARRAY:{
|
||||
SQObjectPtr& key = v->GetUp(-1);
|
||||
if(sq_isnumeric(key)){
|
||||
if(_array(self)->Get(tointeger(key),v->GetUp(-1))) {
|
||||
if(sq_isnumeric(obj)){
|
||||
if(_array(self)->Get(tointeger(obj),obj)) {
|
||||
return SQ_OK;
|
||||
}
|
||||
}
|
||||
@ -1037,7 +1054,7 @@ SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx)
|
||||
default:
|
||||
v->Pop();
|
||||
return sq_throwerror(v,_SC("rawget works only on array/table/instance and class"));
|
||||
}
|
||||
}
|
||||
v->Pop();
|
||||
return sq_throwerror(v,_SC("the index doesn't exist"));
|
||||
}
|
||||
@ -1120,9 +1137,10 @@ SQRESULT sq_reservestack(HSQUIRRELVM v,SQInteger nsize)
|
||||
|
||||
SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror)
|
||||
{
|
||||
if(type(v->GetUp(-1))==OT_GENERATOR){
|
||||
if (type(v->GetUp(-1)) == OT_GENERATOR)
|
||||
{
|
||||
v->PushNull(); //retval
|
||||
if(!v->Execute(v->GetUp(-2),0,v->_top,v->GetUp(-1),raiseerror,SQVM::ET_RESUME_GENERATOR))
|
||||
if (!v->Execute(v->GetUp(-2), 0, v->_top, v->GetUp(-1), raiseerror, SQVM::ET_RESUME_GENERATOR))
|
||||
{v->Raise_Error(v->_lasterror); return SQ_ERROR;}
|
||||
if(!retval)
|
||||
v->Pop();
|
||||
@ -1192,6 +1210,20 @@ void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook)
|
||||
}
|
||||
}
|
||||
|
||||
SQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v,SQInteger idx)
|
||||
{
|
||||
if(sq_gettop(v) >= 1){
|
||||
SQObjectPtr &ud=stack_get(v,idx);
|
||||
switch( type(ud) ) {
|
||||
case OT_USERDATA: return _userdata(ud)->_hook; break;
|
||||
case OT_INSTANCE: return _instance(ud)->_hook; break;
|
||||
case OT_CLASS: return _class(ud)->_hook; break;
|
||||
default: break; //shutup compiler
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f)
|
||||
{
|
||||
_ss(v)->_compilererrorhandler = f;
|
||||
|
92
external/Squirrel/sqbaselib.cpp
vendored
92
external/Squirrel/sqbaselib.cpp
vendored
@ -13,7 +13,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
bool str2num(const SQChar *s,SQObjectPtr &res,SQInteger base)
|
||||
static bool str2num(const SQChar *s,SQObjectPtr &res,SQInteger base)
|
||||
{
|
||||
SQChar *end;
|
||||
const SQChar *e = s;
|
||||
@ -166,9 +166,11 @@ static SQInteger get_slice_params(HSQUIRRELVM v,SQInteger &sidx,SQInteger &eidx,
|
||||
sidx=0;
|
||||
eidx=0;
|
||||
o=stack_get(v,1);
|
||||
SQObjectPtr &start=stack_get(v,2);
|
||||
if(type(start)!=OT_NULL && sq_isnumeric(start)){
|
||||
sidx=tointeger(start);
|
||||
if(top>1){
|
||||
SQObjectPtr &start=stack_get(v,2);
|
||||
if(type(start)!=OT_NULL && sq_isnumeric(start)){
|
||||
sidx=tointeger(start);
|
||||
}
|
||||
}
|
||||
if(top>2){
|
||||
SQObjectPtr &end=stack_get(v,3);
|
||||
@ -653,7 +655,7 @@ static SQInteger array_find(HSQUIRRELVM v)
|
||||
}
|
||||
|
||||
|
||||
bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret)
|
||||
static bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret)
|
||||
{
|
||||
if(func < 0) {
|
||||
if(!v->ObjCmp(a,b,ret)) return false;
|
||||
@ -679,7 +681,7 @@ bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQ
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bottom, SQInteger func)
|
||||
static bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bottom, SQInteger func)
|
||||
{
|
||||
SQInteger maxChild;
|
||||
SQInteger done = 0;
|
||||
@ -719,7 +721,7 @@ bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bott
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _hsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger func)
|
||||
static bool _hsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger func)
|
||||
{
|
||||
SQArray *a = _array(arr);
|
||||
SQInteger i;
|
||||
@ -758,7 +760,7 @@ static SQInteger array_slice(HSQUIRRELVM v)
|
||||
if(sidx < 0)sidx = alen + sidx;
|
||||
if(eidx < 0)eidx = alen + eidx;
|
||||
if(eidx < sidx)return sq_throwerror(v,_SC("wrong indexes"));
|
||||
if(eidx > alen)return sq_throwerror(v,_SC("slice out of range"));
|
||||
if(eidx > alen || sidx < 0)return sq_throwerror(v, _SC("slice out of range"));
|
||||
SQArray *arr=SQArray::Create(_ss(v),eidx-sidx);
|
||||
SQObjectPtr t;
|
||||
SQInteger count=0;
|
||||
@ -805,7 +807,7 @@ static SQInteger string_slice(HSQUIRRELVM v)
|
||||
if(sidx < 0)sidx = slen + sidx;
|
||||
if(eidx < 0)eidx = slen + eidx;
|
||||
if(eidx < sidx) return sq_throwerror(v,_SC("wrong indexes"));
|
||||
if(eidx > slen) return sq_throwerror(v,_SC("slice out of range"));
|
||||
if(eidx > slen || sidx < 0) return sq_throwerror(v, _SC("slice out of range"));
|
||||
v->Push(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx));
|
||||
return 1;
|
||||
}
|
||||
@ -829,13 +831,21 @@ static SQInteger string_find(HSQUIRRELVM v)
|
||||
}
|
||||
|
||||
#define STRING_TOFUNCZ(func) static SQInteger string_##func(HSQUIRRELVM v) \
|
||||
{ \
|
||||
SQObject str=stack_get(v,1); \
|
||||
{\
|
||||
SQInteger sidx,eidx; \
|
||||
SQObjectPtr str; \
|
||||
if(SQ_FAILED(get_slice_params(v,sidx,eidx,str)))return -1; \
|
||||
SQInteger slen = _string(str)->_len; \
|
||||
if(sidx < 0)sidx = slen + sidx; \
|
||||
if(eidx < 0)eidx = slen + eidx; \
|
||||
if(eidx < sidx) return sq_throwerror(v,_SC("wrong indexes")); \
|
||||
if(eidx > slen || sidx < 0) return sq_throwerror(v,_SC("slice out of range")); \
|
||||
SQInteger len=_string(str)->_len; \
|
||||
const SQChar *sThis=_stringval(str); \
|
||||
SQChar *sNew=(_ss(v)->GetScratchPad(rsl(len))); \
|
||||
for(SQInteger i=0;i<len;i++) sNew[i]=func(sThis[i]); \
|
||||
v->Push(SQString::Create(_ss(v),sNew,len)); \
|
||||
const SQChar *sthis=_stringval(str); \
|
||||
SQChar *snew=(_ss(v)->GetScratchPad(sq_rsl(len))); \
|
||||
memcpy(snew,sthis,sq_rsl(len));\
|
||||
for(SQInteger i=sidx;i<eidx;i++) snew[i] = func(sthis[i]); \
|
||||
v->Push(SQString::Create(_ss(v),snew,len)); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
@ -848,10 +858,10 @@ SQRegFunction SQSharedState::_string_default_delegate_funcz[]={
|
||||
{_SC("tointeger"),default_delegate_tointeger,-1, _SC("sn")},
|
||||
{_SC("tofloat"),default_delegate_tofloat,1, _SC("s")},
|
||||
{_SC("tostring"),default_delegate_tostring,1, _SC(".")},
|
||||
{_SC("slice"),string_slice,-1, _SC(" s n n")},
|
||||
{_SC("find"),string_find,-2, _SC("s s n ")},
|
||||
{_SC("tolower"),string_tolower,1, _SC("s")},
|
||||
{_SC("toupper"),string_toupper,1, _SC("s")},
|
||||
{_SC("slice"),string_slice,-1, _SC("s n n")},
|
||||
{_SC("find"),string_find,-2, _SC("s s n")},
|
||||
{_SC("tolower"),string_tolower,-1, _SC("s n n")},
|
||||
{_SC("toupper"),string_toupper,-1, _SC("s n n")},
|
||||
{_SC("weakref"),obj_delegate_weakref,1, NULL },
|
||||
{0,0}
|
||||
};
|
||||
@ -1032,7 +1042,7 @@ static SQInteger thread_wakeup(HSQUIRRELVM v)
|
||||
}
|
||||
}
|
||||
|
||||
SQInteger wakeupret = sq_gettop(v)>1?1:0;
|
||||
SQInteger wakeupret = sq_gettop(v)>1?SQTrue:SQFalse;
|
||||
if(wakeupret) {
|
||||
sq_move(thread,v,2);
|
||||
}
|
||||
@ -1051,6 +1061,47 @@ static SQInteger thread_wakeup(HSQUIRRELVM v)
|
||||
return sq_throwerror(v,_SC("wrong parameter"));
|
||||
}
|
||||
|
||||
static SQInteger thread_wakeupthrow(HSQUIRRELVM v)
|
||||
{
|
||||
SQObjectPtr o = stack_get(v,1);
|
||||
if(type(o) == OT_THREAD) {
|
||||
SQVM *thread = _thread(o);
|
||||
SQInteger state = sq_getvmstate(thread);
|
||||
if(state != SQ_VMSTATE_SUSPENDED) {
|
||||
switch(state) {
|
||||
case SQ_VMSTATE_IDLE:
|
||||
return sq_throwerror(v,_SC("cannot wakeup a idle thread"));
|
||||
break;
|
||||
case SQ_VMSTATE_RUNNING:
|
||||
return sq_throwerror(v,_SC("cannot wakeup a running thread"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sq_move(thread,v,2);
|
||||
sq_throwobject(thread);
|
||||
SQBool rethrow_error = SQTrue;
|
||||
if(sq_gettop(v) > 2) {
|
||||
sq_getbool(v,3,&rethrow_error);
|
||||
}
|
||||
if(SQ_SUCCEEDED(sq_wakeupvm(thread,SQFalse,SQTrue,SQTrue,SQTrue))) {
|
||||
sq_move(v,thread,-1);
|
||||
sq_pop(thread,1); //pop retval
|
||||
if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) {
|
||||
sq_settop(thread,1); //pop roottable
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
sq_settop(thread,1);
|
||||
if(rethrow_error) {
|
||||
v->_lasterror = thread->_lasterror;
|
||||
return SQ_ERROR;
|
||||
}
|
||||
return SQ_OK;
|
||||
}
|
||||
return sq_throwerror(v,_SC("wrong parameter"));
|
||||
}
|
||||
|
||||
static SQInteger thread_getstatus(HSQUIRRELVM v)
|
||||
{
|
||||
SQObjectPtr &o = stack_get(v,1);
|
||||
@ -1106,6 +1157,7 @@ static SQInteger thread_getstackinfos(HSQUIRRELVM v)
|
||||
SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = {
|
||||
{_SC("call"), thread_call, -1, _SC("v")},
|
||||
{_SC("wakeup"), thread_wakeup, -1, _SC("v")},
|
||||
{_SC("wakeupthrow"), thread_wakeupthrow, -2, _SC("v.b")},
|
||||
{_SC("getstatus"), thread_getstatus, 1, _SC("v")},
|
||||
{_SC("weakref"),obj_delegate_weakref,1, NULL },
|
||||
{_SC("getstackinfos"),thread_getstackinfos,2, _SC("vn")},
|
||||
|
67
external/Squirrel/sqcompiler.cpp
vendored
67
external/Squirrel/sqcompiler.cpp
vendored
@ -157,7 +157,7 @@ public:
|
||||
void MoveIfCurrentTargetIsLocal() {
|
||||
SQInteger trg = _fs->TopTarget();
|
||||
if(_fs->IsLocal(trg)) {
|
||||
trg = _fs->PopTarget(); //no pops the target and move it
|
||||
trg = _fs->PopTarget(); //pops the target and moves it
|
||||
_fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
|
||||
}
|
||||
}
|
||||
@ -338,6 +338,7 @@ public:
|
||||
_fs->PushTarget(p1);
|
||||
//EmitCompArithLocal(tok, p1, p1, p2);
|
||||
_fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0);
|
||||
_fs->SnoozeOpt();
|
||||
}
|
||||
break;
|
||||
case OBJECT:
|
||||
@ -356,7 +357,9 @@ public:
|
||||
SQInteger tmp = _fs->PushTarget();
|
||||
_fs->AddInstruction(_OP_GETOUTER, tmp, pos);
|
||||
_fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0);
|
||||
_fs->AddInstruction(_OP_SETOUTER, tmp, pos, tmp);
|
||||
_fs->PopTarget();
|
||||
_fs->PopTarget();
|
||||
_fs->AddInstruction(_OP_SETOUTER, _fs->PushTarget(), pos, tmp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -656,6 +659,7 @@ public:
|
||||
case EXPR: Error(_SC("can't '++' or '--' an expression")); break;
|
||||
case OBJECT:
|
||||
case BASE:
|
||||
if(_es.donot_get == true) { Error(_SC("can't '++' or '--' an expression")); break; } //mmh dor this make sense?
|
||||
Emit2ArgsOP(_OP_PINC, diff);
|
||||
break;
|
||||
case LOCAL: {
|
||||
@ -706,7 +710,7 @@ public:
|
||||
}
|
||||
SQInteger Factor()
|
||||
{
|
||||
_es.etype = EXPR;
|
||||
//_es.etype = EXPR;
|
||||
switch(_token)
|
||||
{
|
||||
case TK_STRING_LITERAL:
|
||||
@ -864,6 +868,7 @@ public:
|
||||
case TK___FILE__: _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_sourcename)); Lex(); break;
|
||||
default: Error(_SC("expression expected"));
|
||||
}
|
||||
_es.etype = EXPR;
|
||||
return -1;
|
||||
}
|
||||
void EmitLoadConstInt(SQInteger value,SQInteger target)
|
||||
@ -871,7 +876,7 @@ public:
|
||||
if(target < 0) {
|
||||
target = _fs->PushTarget();
|
||||
}
|
||||
if((value & (~((SQInteger)0xFFFFFFFF))) == 0) { //does it fit in 32 bits?
|
||||
if(value <= INT_MAX && value > INT_MIN) { //does it fit in 32 bits?
|
||||
_fs->AddInstruction(_OP_LOADINT, target,value);
|
||||
}
|
||||
else {
|
||||
@ -900,8 +905,13 @@ public:
|
||||
{
|
||||
switch(_token) {
|
||||
case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ:
|
||||
case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS:
|
||||
case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ:
|
||||
return false;
|
||||
case TK_PLUSPLUS: case TK_MINUSMINUS:
|
||||
if (!IsEndOfStatement()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('['))));
|
||||
}
|
||||
@ -1017,6 +1027,28 @@ public:
|
||||
if(_token == _SC(',')) Lex(); else break;
|
||||
} while(1);
|
||||
}
|
||||
void IfBlock()
|
||||
{
|
||||
if (_token == _SC('{'))
|
||||
{
|
||||
BEGIN_SCOPE();
|
||||
Lex();
|
||||
Statements();
|
||||
Expect(_SC('}'));
|
||||
if (true) {
|
||||
END_SCOPE();
|
||||
}
|
||||
else {
|
||||
END_SCOPE_NO_CLOSE();
|
||||
}
|
||||
}
|
||||
else {
|
||||
//BEGIN_SCOPE();
|
||||
Statement();
|
||||
if (_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
|
||||
//END_SCOPE();
|
||||
}
|
||||
}
|
||||
void IfStatement()
|
||||
{
|
||||
SQInteger jmppos;
|
||||
@ -1024,22 +1056,33 @@ public:
|
||||
Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
|
||||
_fs->AddInstruction(_OP_JZ, _fs->PopTarget());
|
||||
SQInteger jnepos = _fs->GetCurrentPos();
|
||||
BEGIN_SCOPE();
|
||||
|
||||
Statement();
|
||||
|
||||
|
||||
IfBlock();
|
||||
//
|
||||
if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();
|
||||
/*static int n = 0;
|
||||
if (_token != _SC('}') && _token != TK_ELSE) {
|
||||
printf("IF %d-----------------------!!!!!!!!!\n", n);
|
||||
if (n == 5)
|
||||
{
|
||||
printf("asd");
|
||||
}
|
||||
n++;
|
||||
//OptionalSemicolon();
|
||||
}*/
|
||||
|
||||
|
||||
END_SCOPE();
|
||||
SQInteger endifblock = _fs->GetCurrentPos();
|
||||
if(_token == TK_ELSE){
|
||||
haselse = true;
|
||||
BEGIN_SCOPE();
|
||||
//BEGIN_SCOPE();
|
||||
_fs->AddInstruction(_OP_JMP);
|
||||
jmppos = _fs->GetCurrentPos();
|
||||
Lex();
|
||||
Statement(); if(_lex._prevtoken != _SC('}')) OptionalSemicolon();
|
||||
END_SCOPE();
|
||||
//Statement(); if(_lex._prevtoken != _SC('}')) OptionalSemicolon();
|
||||
IfBlock();
|
||||
//END_SCOPE();
|
||||
_fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
|
||||
}
|
||||
_fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
|
||||
|
6
external/Squirrel/sqdebug.cpp
vendored
6
external/Squirrel/sqdebug.cpp
vendored
@ -61,7 +61,7 @@ void SQVM::Raise_Error(const SQChar *s, ...)
|
||||
va_list vl;
|
||||
va_start(vl, s);
|
||||
SQInteger buffersize = (SQInteger)scstrlen(s)+(NUMBER_MAX_CHAR*2);
|
||||
scvsprintf(_sp(rsl(buffersize)),buffersize, s, vl);
|
||||
scvsprintf(_sp(sq_rsl(buffersize)),buffersize, s, vl);
|
||||
va_end(vl);
|
||||
_lasterror = SQString::Create(_ss(this),_spval,-1);
|
||||
}
|
||||
@ -76,11 +76,11 @@ SQString *SQVM::PrintObjVal(const SQObjectPtr &o)
|
||||
switch(type(o)) {
|
||||
case OT_STRING: return _string(o);
|
||||
case OT_INTEGER:
|
||||
scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),rsl(NUMBER_MAX_CHAR), _PRINT_INT_FMT, _integer(o));
|
||||
scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)),sq_rsl(NUMBER_MAX_CHAR), _PRINT_INT_FMT, _integer(o));
|
||||
return SQString::Create(_ss(this), _spval);
|
||||
break;
|
||||
case OT_FLOAT:
|
||||
scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), rsl(NUMBER_MAX_CHAR), _SC("%.14g"), _float(o));
|
||||
scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)), sq_rsl(NUMBER_MAX_CHAR), _SC("%.14g"), _float(o));
|
||||
return SQString::Create(_ss(this), _spval);
|
||||
break;
|
||||
default:
|
||||
|
1
external/Squirrel/sqfuncstate.cpp
vendored
1
external/Squirrel/sqfuncstate.cpp
vendored
@ -73,7 +73,6 @@ SQInstructionDesc g_InstrDesc[]={
|
||||
{_SC("_OP_NEWSLOTA")},
|
||||
{_SC("_OP_GETBASE")},
|
||||
{_SC("_OP_CLOSE")},
|
||||
{_SC("_OP_JCMP")}
|
||||
};
|
||||
#endif
|
||||
void DumpLiteral(SQObjectPtr &o)
|
||||
|
2
external/Squirrel/sqlexer.cpp
vendored
2
external/Squirrel/sqlexer.cpp
vendored
@ -29,7 +29,7 @@ void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,Compile
|
||||
_errfunc = efunc;
|
||||
_errtarget = ed;
|
||||
_sharedstate = ss;
|
||||
_keywords = SQTable::Create(ss, 26);
|
||||
_keywords = SQTable::Create(ss, 37);
|
||||
ADD_KEYWORD(while, TK_WHILE);
|
||||
ADD_KEYWORD(do, TK_DO);
|
||||
ADD_KEYWORD(if, TK_IF);
|
||||
|
2
external/Squirrel/sqmem.cpp
vendored
2
external/Squirrel/sqmem.cpp
vendored
@ -2,8 +2,10 @@
|
||||
see copyright notice in squirrel.h
|
||||
*/
|
||||
#include "sqpcheader.h"
|
||||
#ifndef SQ_EXCLUDE_DEFAULT_MEMFUNCTIONS
|
||||
void *sq_vm_malloc(SQUnsignedInteger size){ return malloc(size); }
|
||||
|
||||
void *sq_vm_realloc(void *p, SQUnsignedInteger oldsize, SQUnsignedInteger size){ return realloc(p, size); }
|
||||
|
||||
void sq_vm_free(void *p, SQUnsignedInteger size){ free(p); }
|
||||
#endif
|
||||
|
16
external/Squirrel/sqobject.cpp
vendored
16
external/Squirrel/sqobject.cpp
vendored
@ -86,6 +86,9 @@ SQWeakRef *SQRefCounted::GetWeakRef(SQObjectType type)
|
||||
{
|
||||
if(!_weakref) {
|
||||
sq_new(_weakref,SQWeakRef);
|
||||
#if defined(SQUSEDOUBLE) && !defined(_SQ64)
|
||||
_weakref->_obj._unVal.raw = 0; //clean the whole union on 32 bits with double
|
||||
#endif
|
||||
_weakref->_obj._type = type;
|
||||
_weakref->_obj._unVal.pRefCounted = this;
|
||||
}
|
||||
@ -150,6 +153,10 @@ bool SQGenerator::Yield(SQVM *v,SQInteger target)
|
||||
for(SQInteger i=0;i<_ci._etraps;i++) {
|
||||
_etraps.push_back(v->_etraps.top());
|
||||
v->_etraps.pop_back();
|
||||
// store relative stack base and size in case of resume to other _top
|
||||
SQExceptionTrap &et = _etraps.back();
|
||||
et._stackbase -= v->_stackbase;
|
||||
et._stacksize -= v->_stackbase;
|
||||
}
|
||||
_state=eSuspended;
|
||||
return true;
|
||||
@ -162,6 +169,7 @@ bool SQGenerator::Resume(SQVM *v,SQObjectPtr &dest)
|
||||
SQInteger size = _stack.size();
|
||||
SQInteger target = &dest - &(v->_stack._vals[v->_stackbase]);
|
||||
assert(target>=0 && target<=255);
|
||||
SQInteger newbase = v->_top;
|
||||
if(!v->EnterFrame(v->_top, v->_top + size, false))
|
||||
return false;
|
||||
v->ci->_generator = this;
|
||||
@ -177,6 +185,10 @@ bool SQGenerator::Resume(SQVM *v,SQObjectPtr &dest)
|
||||
for(SQInteger i=0;i<_ci._etraps;i++) {
|
||||
v->_etraps.push_back(_etraps.top());
|
||||
_etraps.pop_back();
|
||||
SQExceptionTrap &et = v->_etraps.back();
|
||||
// restore absolute stack base and size
|
||||
et._stackbase += newbase;
|
||||
et._stacksize += newbase;
|
||||
}
|
||||
SQObject _this = _stack._vals[0];
|
||||
v->_stack[v->_stackbase] = type(_this) == OT_WEAKREF ? _weakref(_this)->_obj : _this;
|
||||
@ -305,7 +317,7 @@ bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o
|
||||
switch(type(o)){
|
||||
case OT_STRING:
|
||||
_CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger)));
|
||||
_CHECK_IO(SafeWrite(v,write,up,_stringval(o),rsl(_string(o)->_len)));
|
||||
_CHECK_IO(SafeWrite(v,write,up,_stringval(o),sq_rsl(_string(o)->_len)));
|
||||
break;
|
||||
case OT_BOOL:
|
||||
case OT_INTEGER:
|
||||
@ -330,7 +342,7 @@ bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o)
|
||||
case OT_STRING:{
|
||||
SQInteger len;
|
||||
_CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger)));
|
||||
_CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(rsl(len)),rsl(len)));
|
||||
_CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(sq_rsl(len)),sq_rsl(len)));
|
||||
o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len);
|
||||
}
|
||||
break;
|
||||
|
2
external/Squirrel/sqopcodes.h
vendored
2
external/Squirrel/sqopcodes.h
vendored
@ -99,7 +99,7 @@ enum SQOpcode
|
||||
_OP_THROW= 0x39,
|
||||
_OP_NEWSLOTA= 0x3A,
|
||||
_OP_GETBASE= 0x3B,
|
||||
_OP_CLOSE= 0x3C,
|
||||
_OP_CLOSE= 0x3C
|
||||
};
|
||||
|
||||
struct SQInstructionDesc {
|
||||
|
1
external/Squirrel/sqpcheader.h
vendored
1
external/Squirrel/sqpcheader.h
vendored
@ -6,6 +6,7 @@
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
8
external/Squirrel/sqstate.cpp
vendored
8
external/Squirrel/sqstate.cpp
vendored
@ -596,14 +596,14 @@ SQString *SQStringTable::Add(const SQChar *news,SQInteger len)
|
||||
SQHash h = newhash&(_numofslots-1);
|
||||
SQString *s;
|
||||
for (s = _strings[h]; s; s = s->_next){
|
||||
if(s->_len == len && (!memcmp(news,s->_val,rsl(len))))
|
||||
if(s->_len == len && (!memcmp(news,s->_val,sq_rsl(len))))
|
||||
return s; //found
|
||||
}
|
||||
|
||||
SQString *t = (SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString));
|
||||
SQString *t = (SQString *)SQ_MALLOC(sq_rsl(len)+sizeof(SQString));
|
||||
new (t) SQString;
|
||||
t->_sharedstate = _sharedstate;
|
||||
memcpy(t->_val,news,rsl(len));
|
||||
memcpy(t->_val,news,sq_rsl(len));
|
||||
t->_val[len] = _SC('\0');
|
||||
t->_len = len;
|
||||
t->_hash = newhash;
|
||||
@ -648,7 +648,7 @@ void SQStringTable::Remove(SQString *bs)
|
||||
_slotused--;
|
||||
SQInteger slen = s->_len;
|
||||
s->~SQString();
|
||||
SQ_FREE(s,sizeof(SQString) + rsl(slen));
|
||||
SQ_FREE(s,sizeof(SQString) + sq_rsl(slen));
|
||||
return;
|
||||
}
|
||||
prev = s;
|
||||
|
8
external/Squirrel/sqstate.h
vendored
8
external/Squirrel/sqstate.h
vendored
@ -130,14 +130,6 @@ private:
|
||||
#define _instance_ddel _table(_sharedstate->_instance_default_delegate)
|
||||
#define _weakref_ddel _table(_sharedstate->_weakref_default_delegate)
|
||||
|
||||
#ifdef SQUNICODE //rsl REAL STRING LEN
|
||||
#define rsl(l) ((l)<<WCHAR_SHIFT_MUL)
|
||||
#else
|
||||
#define rsl(l) (l)
|
||||
#endif
|
||||
|
||||
//extern SQObjectPtr _null_;
|
||||
|
||||
bool CompileTypemask(SQIntVec &res,const SQChar *typemask);
|
||||
|
||||
|
||||
|
66
external/Squirrel/sqvm.cpp
vendored
66
external/Squirrel/sqvm.cpp
vendored
@ -68,12 +68,14 @@ bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,
|
||||
switch(op) {
|
||||
case '+': res = i1 + i2; break;
|
||||
case '-': res = i1 - i2; break;
|
||||
case '/': if(i2 == 0) { Raise_Error(_SC("division by zero")); return false; }
|
||||
res = i1 / i2;
|
||||
case '/': if (i2 == 0) { Raise_Error(_SC("division by zero")); return false; }
|
||||
else if (i2 == -1 && i1 == INT_MIN) { Raise_Error(_SC("integer overflow")); return false; }
|
||||
res = i1 / i2;
|
||||
break;
|
||||
case '*': res = i1 * i2; break;
|
||||
case '%': if(i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; }
|
||||
res = i1 % i2;
|
||||
case '%': if (i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; }
|
||||
else if (i2 == -1 && i1 == INT_MIN) { res = 0; break; }
|
||||
res = i1 % i2;
|
||||
break;
|
||||
default: res = 0xDEADBEEF;
|
||||
}
|
||||
@ -284,13 +286,13 @@ bool SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)
|
||||
res = o;
|
||||
return true;
|
||||
case OT_FLOAT:
|
||||
scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),rsl(NUMBER_MAX_CHAR),_SC("%g"),_float(o));
|
||||
scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)),sq_rsl(NUMBER_MAX_CHAR),_SC("%g"),_float(o));
|
||||
break;
|
||||
case OT_INTEGER:
|
||||
scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),rsl(NUMBER_MAX_CHAR),_PRINT_INT_FMT,_integer(o));
|
||||
scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)),sq_rsl(NUMBER_MAX_CHAR),_PRINT_INT_FMT,_integer(o));
|
||||
break;
|
||||
case OT_BOOL:
|
||||
scsprintf(_sp(rsl(6)),rsl(6),_integer(o)?_SC("true"):_SC("false"));
|
||||
scsprintf(_sp(sq_rsl(6)),sq_rsl(6),_integer(o)?_SC("true"):_SC("false"));
|
||||
break;
|
||||
case OT_TABLE:
|
||||
case OT_USERDATA:
|
||||
@ -309,7 +311,7 @@ bool SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)
|
||||
}
|
||||
}
|
||||
default:
|
||||
scsprintf(_sp(rsl(sizeof(void*)+20)),rsl(sizeof(void*)+20),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o));
|
||||
scsprintf(_sp(sq_rsl((sizeof(void*)*2)+NUMBER_MAX_CHAR)),sq_rsl((sizeof(void*)*2)+NUMBER_MAX_CHAR),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o));
|
||||
}
|
||||
res = SQString::Create(_ss(this),_spval);
|
||||
return true;
|
||||
@ -322,9 +324,9 @@ bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &
|
||||
if(!ToString(str, a)) return false;
|
||||
if(!ToString(obj, b)) return false;
|
||||
SQInteger l = _string(a)->_len , ol = _string(b)->_len;
|
||||
SQChar *s = _sp(rsl(l + ol + 1));
|
||||
memcpy(s, _stringval(a), rsl(l));
|
||||
memcpy(s + l, _stringval(b), rsl(ol));
|
||||
SQChar *s = _sp(sq_rsl(l + ol + 1));
|
||||
memcpy(s, _stringval(a), sq_rsl(l));
|
||||
memcpy(s + l, _stringval(b), sq_rsl(ol));
|
||||
dest = SQString::Create(_ss(this), _spval, l + ol);
|
||||
return true;
|
||||
}
|
||||
@ -485,7 +487,7 @@ bool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObject
|
||||
bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix,SQInteger selfidx)
|
||||
{
|
||||
SQObjectPtr tmp, tself = self, tkey = key;
|
||||
if (!Get(tself, tkey, tmp, false, selfidx)) { return false; }
|
||||
if (!Get(tself, tkey, tmp, 0, selfidx)) { return false; }
|
||||
_RET_ON_FAIL(ARITH_OP( op , target, tmp, incr))
|
||||
if (!Set(tself, tkey, target,selfidx)) { return false; }
|
||||
if (postfix) target = tmp;
|
||||
@ -539,7 +541,7 @@ bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr
|
||||
if(CallMetaMethod(closure, MT_NEXTI, 2, itr)) {
|
||||
o4 = o2 = itr;
|
||||
if(type(itr) == OT_NULL) _FINISH(exitpos);
|
||||
if(!Get(o1, itr, o3, false, DONT_FALL_BACK)) {
|
||||
if(!Get(o1, itr, o3, 0, DONT_FALL_BACK)) {
|
||||
Raise_Error(_SC("_nexti returned an invalid idx")); // cloud be changed
|
||||
return false;
|
||||
}
|
||||
@ -713,7 +715,7 @@ exception_restore:
|
||||
#ifndef _SQ64
|
||||
TARGET = (SQInteger)arg1; continue;
|
||||
#else
|
||||
TARGET = (SQInteger)((SQUnsignedInteger32)arg1); continue;
|
||||
TARGET = (SQInteger)((SQInt32)arg1); continue;
|
||||
#endif
|
||||
case _OP_LOADFLOAT: TARGET = *((SQFloat *)&arg1); continue;
|
||||
case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue;
|
||||
@ -800,7 +802,7 @@ exception_restore:
|
||||
case _OP_PREPCALLK: {
|
||||
SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1);
|
||||
SQObjectPtr &o = STK(arg2);
|
||||
if (!Get(o, key, temp_reg,false,arg2)) {
|
||||
if (!Get(o, key, temp_reg,0,arg2)) {
|
||||
SQ_THROW();
|
||||
}
|
||||
STK(arg3) = o;
|
||||
@ -808,7 +810,7 @@ exception_restore:
|
||||
}
|
||||
continue;
|
||||
case _OP_GETK:
|
||||
if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, false,arg2)) { SQ_THROW();}
|
||||
if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, 0,arg2)) { SQ_THROW();}
|
||||
_Swap(TARGET,temp_reg);//TARGET = temp_reg;
|
||||
continue;
|
||||
case _OP_MOVE: TARGET = STK(arg1); continue;
|
||||
@ -822,7 +824,7 @@ exception_restore:
|
||||
if (arg0 != 0xFF) TARGET = STK(arg3);
|
||||
continue;
|
||||
case _OP_GET:
|
||||
if (!Get(STK(arg1), STK(arg2), temp_reg, false,arg1)) { SQ_THROW(); }
|
||||
if (!Get(STK(arg1), STK(arg2), temp_reg, 0,arg1)) { SQ_THROW(); }
|
||||
_Swap(TARGET,temp_reg);//TARGET = temp_reg;
|
||||
continue;
|
||||
case _OP_EQ:{
|
||||
@ -907,7 +909,7 @@ exception_restore:
|
||||
#ifndef _SQ64
|
||||
val._unVal.nInteger = (SQInteger)arg1;
|
||||
#else
|
||||
val._unVal.nInteger = (SQInteger)((SQUnsignedInteger32)arg1);
|
||||
val._unVal.nInteger = (SQInteger)((SQInt32)arg1);
|
||||
#endif
|
||||
break;
|
||||
case AAT_FLOAT:
|
||||
@ -918,7 +920,7 @@ exception_restore:
|
||||
val._type = OT_BOOL;
|
||||
val._unVal.nInteger = arg1;
|
||||
break;
|
||||
default: assert(0); break;
|
||||
default: val._type = OT_INTEGER; assert(0); break;
|
||||
|
||||
}
|
||||
_array(STK(arg0))->Append(val); continue;
|
||||
@ -952,7 +954,7 @@ exception_restore:
|
||||
|
||||
} continue;
|
||||
case _OP_CMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET)) continue;
|
||||
case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true, EXISTS_FALL_BACK)?true:false;continue;
|
||||
case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, GET_FLAG_DO_NOT_RAISE_ERROR | GET_FLAG_RAW, DONT_FALL_BACK) ? true : false; continue;
|
||||
case _OP_INSTANCEOF:
|
||||
if(type(STK(arg1)) != OT_CLASS)
|
||||
{Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();}
|
||||
@ -1198,14 +1200,14 @@ bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newb
|
||||
#define FALLBACK_NO_MATCH 1
|
||||
#define FALLBACK_ERROR 2
|
||||
|
||||
bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, SQInteger selfidx)
|
||||
bool SQVM::Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, SQUnsignedInteger getflags, SQInteger selfidx)
|
||||
{
|
||||
switch(type(self)){
|
||||
case OT_TABLE:
|
||||
if(_table(self)->Get(key,dest))return true;
|
||||
break;
|
||||
case OT_ARRAY:
|
||||
if(sq_isnumeric(key)) { if(_array(self)->Get(tointeger(key),dest)) { return true; } if(selfidx != EXISTS_FALL_BACK) Raise_IdxError(key); return false; }
|
||||
if (sq_isnumeric(key)) { if (_array(self)->Get(tointeger(key), dest)) { return true; } if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key); return false; }
|
||||
break;
|
||||
case OT_INSTANCE:
|
||||
if(_instance(self)->Get(key,dest)) return true;
|
||||
@ -1216,18 +1218,19 @@ bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,
|
||||
case OT_STRING:
|
||||
if(sq_isnumeric(key)){
|
||||
SQInteger n = tointeger(key);
|
||||
if(abs((int)n) < _string(self)->_len) {
|
||||
if(n < 0) n = _string(self)->_len - n;
|
||||
SQInteger len = _string(self)->_len;
|
||||
if (n < 0) { n += len; }
|
||||
if (n >= 0 && n < len) {
|
||||
dest = SQInteger(_stringval(self)[n]);
|
||||
return true;
|
||||
}
|
||||
if(selfidx != EXISTS_FALL_BACK) Raise_IdxError(key);
|
||||
if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:break; //shut up compiler
|
||||
}
|
||||
if(!raw) {
|
||||
if ((getflags & GET_FLAG_RAW) == 0) {
|
||||
switch(FallBackGet(self,key,dest)) {
|
||||
case FALLBACK_OK: return true; //okie
|
||||
case FALLBACK_NO_MATCH: break; //keep falling back
|
||||
@ -1242,12 +1245,12 @@ bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,
|
||||
SQWeakRef *w = _closure(ci->_closure)->_root;
|
||||
if(type(w->_obj) != OT_NULL)
|
||||
{
|
||||
if(Get(*((const SQObjectPtr *)&w->_obj),key,dest,false,DONT_FALL_BACK)) return true;
|
||||
if(Get(*((const SQObjectPtr *)&w->_obj),key,dest,0,DONT_FALL_BACK)) return true;
|
||||
}
|
||||
|
||||
}
|
||||
//#endif
|
||||
if(selfidx != EXISTS_FALL_BACK) Raise_IdxError(key);
|
||||
if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1278,7 +1281,7 @@ SQInteger SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObj
|
||||
case OT_USERDATA:
|
||||
//delegation
|
||||
if(_delegable(self)->_delegate) {
|
||||
if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,false,DONT_FALL_BACK)) return FALLBACK_OK;
|
||||
if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,0,DONT_FALL_BACK)) return FALLBACK_OK;
|
||||
}
|
||||
else {
|
||||
return FALLBACK_NO_MATCH;
|
||||
@ -1551,7 +1554,8 @@ SQInteger prevstackbase = _stackbase;
|
||||
SQObjectPtr constr;
|
||||
SQObjectPtr temp;
|
||||
CreateClassInstance(_class(closure),outres,constr);
|
||||
if(type(constr) != OT_NULL) {
|
||||
SQObjectType ctype = type(constr);
|
||||
if (ctype == OT_NATIVECLOSURE || ctype == OT_CLOSURE) {
|
||||
_stack[stackbase] = outres;
|
||||
return Call(constr,nparams,stackbase,temp,raiseerror);
|
||||
}
|
||||
@ -1631,7 +1635,7 @@ bool SQVM::EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall)
|
||||
Raise_Error(_SC("stack overflow, cannot resize stack while in a metamethod"));
|
||||
return false;
|
||||
}
|
||||
_stack.resize(_stack.size() + (MIN_STACK_OVERHEAD << 2));
|
||||
_stack.resize(newtop + (MIN_STACK_OVERHEAD << 2));
|
||||
RelocateOuters();
|
||||
}
|
||||
return true;
|
||||
|
7
external/Squirrel/sqvm.h
vendored
7
external/Squirrel/sqvm.h
vendored
@ -9,7 +9,10 @@
|
||||
|
||||
#define SQ_SUSPEND_FLAG -666
|
||||
#define DONT_FALL_BACK 666
|
||||
#define EXISTS_FALL_BACK -1
|
||||
//#define EXISTS_FALL_BACK -1
|
||||
|
||||
#define GET_FLAG_RAW 0x00000001
|
||||
#define GET_FLAG_DO_NOT_RAISE_ERROR 0x00000002
|
||||
//base lib
|
||||
void sq_base_register(HSQUIRRELVM v);
|
||||
|
||||
@ -66,7 +69,7 @@ public:
|
||||
|
||||
void CallDebugHook(SQInteger type,SQInteger forcedline=0);
|
||||
void CallErrorHandler(SQObjectPtr &e);
|
||||
bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, SQInteger selfidx);
|
||||
bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, SQUnsignedInteger getflags, SQInteger selfidx);
|
||||
SQInteger FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest);
|
||||
bool InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest);
|
||||
bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, SQInteger selfidx);
|
||||
|
Reference in New Issue
Block a user