From e1dadf2dbdd2bcf65517310498ded03c821e463e Mon Sep 17 00:00:00 2001 From: zwer Date: Tue, 24 Jan 2006 13:11:45 +0000 Subject: Im Projektarchiv verschoben git-svn-id: svn://svn.berlios.de/ffnetdev/trunk@4 1f4bef6d-8e0a-0410-8695-e467da8aaccf --- develop/src/tools/select.c | 49 +++++++++++++ develop/src/tools/select.h | 75 ++++++++++++++++++++ develop/src/tools/socket.c | 135 ++++++++++++++++++++++++++++++++++++ develop/src/tools/socket.h | 108 +++++++++++++++++++++++++++++ develop/src/tools/source.c | 169 +++++++++++++++++++++++++++++++++++++++++++++ develop/src/tools/source.h | 109 +++++++++++++++++++++++++++++ develop/src/tools/tools.c | 12 ++++ develop/src/tools/tools.h | 67 ++++++++++++++++++ tools/select.c | 49 ------------- tools/select.h | 75 -------------------- tools/socket.c | 135 ------------------------------------ tools/socket.h | 108 ----------------------------- tools/source.c | 169 --------------------------------------------- tools/source.h | 109 ----------------------------- tools/tools.c | 12 ---- tools/tools.h | 67 ------------------ 16 files changed, 724 insertions(+), 724 deletions(-) create mode 100644 develop/src/tools/select.c create mode 100644 develop/src/tools/select.h create mode 100644 develop/src/tools/socket.c create mode 100644 develop/src/tools/socket.h create mode 100644 develop/src/tools/source.c create mode 100644 develop/src/tools/source.h create mode 100644 develop/src/tools/tools.c create mode 100644 develop/src/tools/tools.h delete mode 100644 tools/select.c delete mode 100644 tools/select.h delete mode 100644 tools/socket.c delete mode 100644 tools/socket.h delete mode 100644 tools/source.c delete mode 100644 tools/source.h delete mode 100644 tools/tools.c delete mode 100644 tools/tools.h diff --git a/develop/src/tools/select.c b/develop/src/tools/select.c new file mode 100644 index 0000000..0ab5f9b --- /dev/null +++ b/develop/src/tools/select.c @@ -0,0 +1,49 @@ +#include "tools/select.h" + +#include +#include +#include +#include +#include +#include + +cTBSelect::cTBSelect(void) { + Clear(); +} + +cTBSelect::~cTBSelect() { +} + +int cTBSelect::Select(uint TimeoutMs) { + struct timeval tv; + ssize_t res; + int ms; + + tv.tv_usec = (TimeoutMs % 1000) * 1000; + tv.tv_sec = TimeoutMs / 1000; + + if (TimeoutMs == 0) + return ::select(m_MaxFiled + 1, &m_Rfds, &m_Wfds, NULL, &tv); + + cTimeMs starttime; + ms = TimeoutMs; + while (ms > 0 && (res = ::select(m_MaxFiled + 1, &m_Rfds, &m_Wfds, NULL, + &tv)) == -1 && errno == EINTR) { + ms = TimeoutMs - starttime.Elapsed(); + tv.tv_usec = (ms % 1000) * 1000; + tv.tv_sec = ms / 1000; + } + if (ms <= 0) { + errno = ETIMEDOUT; + return -1; + } + return res; +} + +int cTBSelect::Select(void) { + ssize_t res; + while ((res = ::select(m_MaxFiled + 1, &m_Rfds, &m_Wfds, NULL, NULL)) == -1 + && errno == EINTR) + ; + return res; +} diff --git a/develop/src/tools/select.h b/develop/src/tools/select.h new file mode 100644 index 0000000..7e873e2 --- /dev/null +++ b/develop/src/tools/select.h @@ -0,0 +1,75 @@ +#ifndef TOOLBOX_SELECT_H +#define TOOLBOX_SELECT_H + +#include "tools/tools.h" + +#include + +/* cTBSelect provides an interface for polling UNIX-like file descriptors. */ + +class cTBSelect { +private: + int m_MaxFiled; + + fd_set m_Rfds; + fd_set m_Wfds; + +public: + cTBSelect(void); + virtual ~cTBSelect(); + + /* Clear() resets the object for use in a new Select() call. All file + descriptors and their previous states are invalidated. */ + virtual void Clear(void); + + /* Add() adds a file descriptor to be polled in the next Select() call. + That call polls if the file is readable if Output is set to false, + writeable otherwise. */ + virtual bool Add(int Filed, bool Output = false); + + /* Select() polls all descriptors added by Add() and returns as soon as + one of those changes state (gets readable/writeable), or after + TimeoutMs milliseconds, whichever happens first. It returns the number + of filedescriptors that have changed state. On error, -1 is returned + and errno is set appropriately. */ + virtual int Select(uint TimeoutMs); + + /* Select() polls all descriptors added by Add() and returns as soon as + one of those changes state (gets readable/writeable). It returns the + number of filedescriptors that have changed state. On error, -1 is + returned and errno is set appropriately. */ + virtual int Select(void); + + /* CanRead() returns true if the descriptor has changed to readable during + the last Select() call. Otherwise false is returned. */ + virtual bool CanRead(int FileNo) const; + + /* CanWrite() returns true if the descriptor has changed to writeable + during the last Select() call. Otherwise false is returned. */ + virtual bool CanWrite(int FileNo) const; +}; + +inline void cTBSelect::Clear(void) { + FD_ZERO(&m_Rfds); + FD_ZERO(&m_Wfds); + m_MaxFiled = -1; +} + +inline bool cTBSelect::Add(int Filed, bool Output /* = false */) { + if (Filed < 0) return false; + FD_SET(Filed, Output ? &m_Wfds : &m_Rfds); + if (Filed > m_MaxFiled) m_MaxFiled = Filed; + return true; +} + +inline bool cTBSelect::CanRead(int FileNo) const { + if (FileNo < 0) return false; + return FD_ISSET(FileNo, &m_Rfds); +} + +inline bool cTBSelect::CanWrite(int FileNo) const { + if (FileNo < 0) return false; + return FD_ISSET(FileNo, &m_Wfds); +} + +#endif // TOOLBOX_SELECT_H diff --git a/develop/src/tools/socket.c b/develop/src/tools/socket.c new file mode 100644 index 0000000..3e3be65 --- /dev/null +++ b/develop/src/tools/socket.c @@ -0,0 +1,135 @@ +#include "tools/socket.h" + +#include +#include +#include +#include +#include + +cTBSocket::cTBSocket(int Type) { + memset(&m_LocalAddr, 0, sizeof(m_LocalAddr)); + memset(&m_RemoteAddr, 0, sizeof(m_RemoteAddr)); + m_Type = Type; +} + +cTBSocket::~cTBSocket() { + if (IsOpen()) Close(); +} + +bool cTBSocket::Connect(const std::string &Host, unsigned int Port) { + socklen_t len; + int socket; + + if (IsOpen()) Close(); + + if ((socket = ::socket(PF_INET, m_Type, IPPROTO_IP)) == -1) + return false; + + m_LocalAddr.sin_family = AF_INET; + m_LocalAddr.sin_port = 0; + m_LocalAddr.sin_addr.s_addr = INADDR_ANY; + if (::bind(socket, (struct sockaddr*)&m_LocalAddr, sizeof(m_LocalAddr)) + == -1) + return false; + + m_RemoteAddr.sin_family = AF_INET; + m_RemoteAddr.sin_port = htons(Port); + m_RemoteAddr.sin_addr.s_addr = inet_addr(Host.c_str()); + if (::connect(socket, (struct sockaddr*)&m_RemoteAddr, + sizeof(m_RemoteAddr)) == -1) + return false; + + len = sizeof(struct sockaddr_in); + if (::getpeername(socket, (struct sockaddr*)&m_RemoteAddr, &len) == -1) + return false; + + len = sizeof(struct sockaddr_in); + if (::getsockname(socket, (struct sockaddr*)&m_LocalAddr, &len) == -1) + return false; + + return cTBSource::Open(socket); +} + +bool cTBSocket::Listen(const std::string &Ip, unsigned int Port, int BackLog) { + int val; + socklen_t len; + int socket; + + if (IsOpen()) Close(); + + if ((socket = ::socket(PF_INET, m_Type, IPPROTO_IP)) == -1) + return false; + + val = 1; + if (::setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == -1) + return false; + + m_LocalAddr.sin_family = AF_INET; + m_LocalAddr.sin_port = htons(Port); + m_LocalAddr.sin_addr.s_addr = inet_addr(Ip.c_str()); + if (::bind(socket, (struct sockaddr*)&m_LocalAddr, sizeof(m_LocalAddr)) + == -1) + return false; + + len = sizeof(struct sockaddr_in); + if (::getsockname(socket, (struct sockaddr*)&m_LocalAddr, &len) == -1) + return false; + + if (m_Type == SOCK_STREAM && ::listen(socket, BackLog) == -1) + return false; + + if (!cTBSource::Open(socket)) + return false; + + return true; +} + +bool cTBSocket::Accept(const cTBSocket &Listener) { + socklen_t addrlen; + int socket; + + if (IsOpen()) Close(); + + addrlen = sizeof(struct sockaddr_in); + if ((socket = ::accept(Listener, (struct sockaddr*)&m_RemoteAddr, + &addrlen)) == -1) + return false; + + addrlen = sizeof(struct sockaddr_in); + if (::getsockname(socket, (struct sockaddr*)&m_LocalAddr, &addrlen) == -1) + return false; + + if (!cTBSource::Open(socket)) + return false; + + return true; +} + +RETURNS(cTBSocket, cTBSocket::Accept(void) const, ret) + ret.Accept(*this); +RETURN(ret) + +bool cTBSocket::Close(void) { + bool ret = true; + + if (!IsOpen()) + ERRNUL(EBADF); + + if (::close(*this) == -1) + ret = false; + + if (!cTBSource::Close()) + ret = false; + + memset(&m_LocalAddr, 0, sizeof(m_LocalAddr)); + memset(&m_RemoteAddr, 0, sizeof(m_RemoteAddr)); + + return ret; +} + +bool cTBSocket::Shutdown(int how) { + if (!IsOpen()) + ERRNUL(EBADF); + + return ::shutdown(*this, how) != -1; +} diff --git a/develop/src/tools/socket.h b/develop/src/tools/socket.h new file mode 100644 index 0000000..d1a7d62 --- /dev/null +++ b/develop/src/tools/socket.h @@ -0,0 +1,108 @@ +#ifndef TOOLBOX_SOCKET_H +#define TOOLBOX_SOCKET_H + +#include "tools/tools.h" +#include "tools/source.h" + +#include +#include +#include +#include + +/* cTBSocket provides a cTBSource-derived interface for input and output on + TCP/IPv4-sockets. */ + +class cTBSocket: public cTBSource { +private: + struct sockaddr_in m_LocalAddr; + struct sockaddr_in m_RemoteAddr; + + int m_Type; + +public: + cTBSocket(int Type = SOCK_STREAM); + virtual ~cTBSocket(); + + /* See cTBSource::SysRead() + Reimplemented for TCP/IPv4 sockets. */ + virtual ssize_t SysRead(void *Buffer, size_t Length) const; + + /* See cTBSource::SysWrite() + Reimplemented for TCP/IPv4 sockets. */ + virtual ssize_t SysWrite(const void *Buffer, size_t Length) const; + + /* Connect() tries to connect an available local socket to the port given + by Port of the target host given by Host in numbers-and-dots notation + (i.e. "212.43.45.21"). Returns true if the connection attempt was + successful and false otherwise, setting errno appropriately. */ + virtual bool Connect(const std::string &Host, uint Port); + + /* Shutdown() shuts down one or both ends of a socket. If called with How + set to SHUT_RD, further reads on this socket will be denied. If called + with SHUT_WR, all writes are denied. Called with SHUT_RDWR, all firther + action on this socket will be denied. Returns true on success and false + otherwise, setting errno appropriately. */ + virtual bool Shutdown(int How); + + /* Close() closes the associated socket and releases all structures. + Returns true on success and false otherwise, setting errno + appropriately. The object is in the closed state afterwards, regardless + of any errors. */ + virtual bool Close(void); + + /* Listen() listens on the local port Port for incoming connections. The + BackLog parameter defines the maximum length the queue of pending + connections may grow to. Returns true if the object is listening on + the specified port and false otherwise, setting errno appropriately. */ + virtual bool Listen(const std::string &Ip, uint Port, int BackLog); + + /* Accept() returns a newly created cTBSocket, which is connected to the + first connection request on the queue of pending connections of a + listening socket. If no connection request was pending, or if any other + error occured, the resulting cTBSocket is closed. */ + virtual cTBSocket Accept(void) const; + + /* Accept() extracts the first connection request on the queue of pending + connections of the listening socket Listener and connects it to this + object. Returns true on success and false otherwise, setting errno to + an appropriate value. */ + virtual bool Accept(const cTBSocket &Listener); + + /* LocalPort() returns the port number this socket is connected to locally. + The result is undefined for a non-open socket. */ + int LocalPort(void) const { return ntohs(m_LocalAddr.sin_port); } + + /* RemotePort() returns the port number this socket is connected to on the + remote side. The result is undefined for a non-open socket. */ + int RemotePort(void) const { return ntohs(m_RemoteAddr.sin_port); } + + /* LocalIp() returns the internet address in numbers-and-dots notation of + the interface this socket is connected to locally. This can be + "0.0.0.0" for a listening socket listening to all interfaces. If the + socket is in its closed state, the result is undefined. */ + std::string LocalIp(void) const { return inet_ntoa(m_LocalAddr.sin_addr); } + + /* RemoteIp() returns the internet address in numbers-and-dots notation of + the interface this socket is connected to on the remote side. If the + socket is in its closed state, the result is undefined. */ + std::string RemoteIp(void) const { return inet_ntoa(m_RemoteAddr.sin_addr); } + + in_addr_t LocalIpAddr(void) const { return m_LocalAddr.sin_addr.s_addr; } + in_addr_t RemoteIpAddr(void) const { return m_RemoteAddr.sin_addr.s_addr; } + + int Type(void) const { return m_Type; } +}; + +inline ssize_t cTBSocket::SysRead(void *Buffer, size_t Length) const { + if (m_Type == SOCK_DGRAM) { + socklen_t len = sizeof(m_RemoteAddr); + return ::recvfrom(*this, Buffer, Length, 0, (sockaddr*)&m_RemoteAddr, &len); + } else + return ::recv(*this, Buffer, Length, 0); +} + +inline ssize_t cTBSocket::SysWrite(const void *Buffer, size_t Length) const { + return ::send(*this, Buffer, Length, 0); +} + +#endif // TOOLBOX_SOCKET_H diff --git a/develop/src/tools/source.c b/develop/src/tools/source.c new file mode 100644 index 0000000..f8751b6 --- /dev/null +++ b/develop/src/tools/source.c @@ -0,0 +1,169 @@ +#include "tools/source.h" +#include "tools/select.h" + +#include +#include +#include +#include +#include + +cTBSource::cTBSource(void) { + m_BytesRead = 0; + m_BytesWritten = 0; + m_Filed = -1; +} + +bool cTBSource::Open(int Filed, bool IsUnixFd) { + if (IsOpen()) + Close(); + + m_Filed = Filed; + if (IsUnixFd && ::fcntl(m_Filed, F_SETFL, O_NONBLOCK) == -1) + return false; + + return true; +} + +cTBSource::~cTBSource() { +} + +bool cTBSource::Close(void) { + if (!IsOpen()) { + errno = EBADF; + return false; + } + + m_Filed = -1; + return true; +} + +ssize_t cTBSource::Read(void *Buffer, size_t Length) { + ssize_t res; + while ((res = SysRead(Buffer, Length)) < 0 && errno == EINTR) + errno = 0; + if (res > 0) m_BytesRead += res; + return res; +} + +ssize_t cTBSource::Write(const void *Buffer, size_t Length) { + ssize_t res; + while ((res = SysWrite(Buffer, Length)) < 0 && errno == EINTR) + errno = 0; + if (res > 0) m_BytesWritten += res; + return res; +} + +bool cTBSource::TimedWrite(const void *Buffer, size_t Length, uint TimeoutMs) { + cTBSelect sel; + int ms, offs; + + cTimeMs starttime; + ms = TimeoutMs; + offs = 0; + while (Length > 0) { + int b; + + sel.Clear(); + sel.Add(m_Filed, true); + if (sel.Select(ms) == -1) + return false; + + if (sel.CanWrite(m_Filed)) { + if ((b = Write((char*)Buffer + offs, Length)) == -1) + return false; + offs += b; + Length -= b; + } + + ms = TimeoutMs - starttime.Elapsed(); + if (ms <= 0) { + errno = ETIMEDOUT; + return false; + } + } + return true; +} + +bool cTBSource::SafeWrite(const void *Buffer, size_t Length) { + cTBSelect sel; + int offs; + + offs = 0; + while (Length > 0) { + int b; + + sel.Clear(); + sel.Add(m_Filed, true); + if (sel.Select() == -1) + return false; + + if (sel.CanWrite(m_Filed)) { + if ((b = Write((char*)Buffer + offs, Length)) == -1) + return false; + offs += b; + Length -= b; + } + + } + return true; +} + +ssize_t cTBSource::ReadUntil(void *Buffer, size_t Length, const char *Seq, + uint TimeoutMs) { + int ms; + size_t len; + cTBSelect sel; + + if ((len = m_LineBuffer.find(Seq)) != (size_t)-1) { + if (len > Length) { + errno = ENOBUFS; + return -1; + } + memcpy(Buffer, m_LineBuffer.data(), len); + m_LineBuffer.erase(0, len + strlen(Seq)); + //Dprintf("ReadUntil: Served from Linebuffer: %d, |%.*s|\n", len, len - 1, + // (char*)Buffer); + return len; + } + + cTimeMs starttime; + ms = TimeoutMs; + while (m_LineBuffer.size() < BUFSIZ) { + sel.Clear(); + sel.Add(m_Filed, false); + + if (sel.Select(ms) == -1) + return -1; + + if (sel.CanRead(m_Filed)) { + int b; + + len = m_LineBuffer.size(); + m_LineBuffer.resize(BUFSIZ); + if ((b = Read((char*)m_LineBuffer.data() + len, BUFSIZ - len)) == -1) + return -1; + m_LineBuffer.resize(len + b); + + if ((len = m_LineBuffer.find(Seq)) != (size_t)-1) { + if (len > Length) { + errno = ENOBUFS; + return -1; + } + memcpy(Buffer, m_LineBuffer.data(), len); + m_LineBuffer.erase(0, len + strlen(Seq)); + //Dprintf("ReadUntil: Served from Linebuffer: %d, |%.*s|\n", len, len - 1, + // (char*)Buffer); + return len; + } + } + + ms = TimeoutMs - starttime.Elapsed(); + if (ms <= 0) { + errno = ETIMEDOUT; + return -1; + } + } + errno = ENOBUFS; + return -1; +} + diff --git a/develop/src/tools/source.h b/develop/src/tools/source.h new file mode 100644 index 0000000..09c4bf3 --- /dev/null +++ b/develop/src/tools/source.h @@ -0,0 +1,109 @@ +#ifndef TOOLBOX_SOURCE_H +#define TOOLBOX_SOURCE_H + +#include "tools/tools.h" + +#include +#include + +/* cTBSource provides an abstract interface for input and output. It can + be used to have common access to different types of UNIX-files. */ + +class cTBSource { +private: + int m_Filed; + + size_t m_BytesRead; + size_t m_BytesWritten; + + std::string m_LineBuffer; + +public: + cTBSource(void); + virtual ~cTBSource(); + + /* SysRead() implements the low-level read on the source. It will store + data into the area pointed to by Buffer, which is at least Length + bytes in size. It will return the exact number of bytes read (which + can be fewer than requested). On error, -1 is returned, and errno + is set to an appropriate value. */ + virtual ssize_t SysRead(void *Buffer, size_t Length) const = 0; + + /* SysWrite() implements the low-level write on the source. It will write + at most Length bytes of the data pointed to by Buffer. It will return + the exact number of bytes written (which can be fewer than requested). + On error, -1 is returned, and errno is set to an appropriate value. */ + virtual ssize_t SysWrite(const void *Buffer, size_t Length) const = 0; + + /* IsOpen() returns true, if this source refers to a valid descriptor. + It is not checked whether this source is really open, so only if + opened by the appropriate Methods this function will return the + correct value */ + virtual bool IsOpen(void) const { return m_Filed != -1; } + + /* Open() associates this source with the descriptor Filed, setting it + to non-blocking mode if IsUnixFd in true. Returns true on success, + and false on error, setting errno to appropriately. + If you want to implement sources that can't be represented by UNIX + filedescriptors, you can use Filed to store any useful information + about the source. + This must be called by any derivations in an appropriate Method (like + open for files, connect for sockets). */ + virtual bool Open(int Filed, bool IsUnixFd = true); + + /* Close() resets the source to the uninitialized state (IsOpen() == false) + and must be called by any derivations after really closing the source. + Returns true on success and false on error, setting errno appropriately. + The object is in closed state afterwards, even if an error occured. */ + virtual bool Close(void); + + /* Read() reads at most Length bytes into the storage pointed to by Buffer, + which must be at least Length bytes in size, using the SysRead()- + Interface. It retries if an EINTR occurs (i.e. the low-level call was + interrupted). It returns the exact number of bytes read (which can be + fewer than requested). On error, -1 is returned, and errno is set + appropriately. */ + ssize_t Read(void *Buffer, size_t Length); + + /* Write() writes at most Length bytes from the storage pointed to by + Buffer, using the SysWrite()-Interface. It retries if EINTR occurs + (i.e. the low-level call was interrupted). It returns the exact number + of bytes written (which can be fewer than requested). On error, -1 is + returned and errno is set appropriately. */ + ssize_t Write(const void *Buffer, size_t Length); + + /* TimedWrite() tries to write Length bytes from the storage pointed to by + Buffer within the time specified by TimeoutMs, using the Write()- + Interface. On success, true is returned. On error, false is returned + and errno is set appropriately. TimedRead only works on UNIX file + descriptor sources. */ + bool TimedWrite(const void *Buffer, size_t Length, uint TimeoutMs); + + bool SafeWrite(const void *Buffer, size_t Length); + + /* ReadUntil() tries to read at most Length bytes into the storage pointed + to by Buffer, which must be at least Length bytes in size, within the + time specified by TimeoutMs, using the Read()-Interface. Reading stops + after the character sequence Seq has been read and on end-of-file. + Returns the number of bytes read (if that is equal to Length, you have + to check if the buffer ends with Seq), or -1 on error, in which case + errno is set appropriately. */ + ssize_t ReadUntil(void *Buffer, size_t Length, const char *Seq, + uint TimeoutMs); + + /* BytesRead() returns the exact number of bytes read through the Read() + method since Close() has been called on this source (or since its + creation). */ + size_t BytesRead(void) const { return m_BytesRead; } + + /* BytesWritten() returns the exact number of bytes written through the + Write() method since Close() has been called on this source (or since + its creation). */ + size_t BytesWritten(void) const { return m_BytesWritten; } + + /* operator int() returns the descriptor (or informative number) associated + with this source. */ + operator int() const { return m_Filed; } +}; + +#endif // TOOLBOX_SOURCE_H diff --git a/develop/src/tools/tools.c b/develop/src/tools/tools.c new file mode 100644 index 0000000..fa813fa --- /dev/null +++ b/develop/src/tools/tools.c @@ -0,0 +1,12 @@ +#include "tools/tools.h" + +#include +#include +#include +#include +#include + +void *operator new(size_t nSize, void *p) throw () { + return p; +} + diff --git a/develop/src/tools/tools.h b/develop/src/tools/tools.h new file mode 100644 index 0000000..ab00c60 --- /dev/null +++ b/develop/src/tools/tools.h @@ -0,0 +1,67 @@ +#ifndef TOOLBOX_TOOLS_H +#define TOOLBOX_TOOLS_H + +//#include +//#include +#include + +//#define KILOBYTE(x) ((x)*1024) +//#define MEGABYTE(x) (KILOBYTE(x)*1024) + +//typedef unsigned int uint; +//typedef unsigned long ulong; +typedef unsigned char uchar; +//typedef unsigned short ushort; + +// Special constructor for CreateElements +void *operator new(size_t, void*) throw (); + +#ifdef TOOLBOX_DEBUG +# define ASSERT(x) if ((x)) cerr << "Warning: ASSERT failed At " << __FILE__ << ":" << __LINE__ << " ["#x"]" << endl +# define CHECK_PTR(x) if (!(x)) cerr << "Warning: Pointer is NULL At " << __FILE__ << ":" << __LINE__ << endl; +# define CHECK_NEXT_ALLOC() _checkNextAlloc() +# define DPRINT(x...) LOGi(x) +#else +# define ASSERT(x) +# define CHECK_PTR(x) +# define CHECK_NEXT_ALLOC() +# define DPRINT(x...) +#endif + +#define ERRNUL(e) {errno=e;return 0;} +#define ERRSYS(e) {errno=e;return -1;} + +/* RETURNS() and RETURN() are macros that can be used if a class object is + being returned. They make use of the GNU C-Compiler's named return value + feature, if available. In this case, the class object isn't returned and + copied, but the result itself is filled. + + RETURNS(ReturnType, FunctionDeclaration, Result) + ... function-body working on Result ... + RETURN(Result) + + A function like this (cXYZ is a class type): + + cXYZ myfunction(int a, char *b) { + cXYZ result; + ... something happens with result ... + return result; + } + + can be written like this: + + RETURNS(cXYZ, myfunction(int a, char *b), result) + ... something happens with result ... + RETURN(result) + + DISABLED SINCE GCC 3.x +*/ +//#ifdef __GNUC__ +//# define RETURNS(t,x,r) t x return r { +//# define RETURN(x) } +//#else +# define RETURNS(t,x,r) t x { t r; +# define RETURN(x) return x; } +//#endif + +#endif // TOOLBOX_TOOLS_H diff --git a/tools/select.c b/tools/select.c deleted file mode 100644 index 0ab5f9b..0000000 --- a/tools/select.c +++ /dev/null @@ -1,49 +0,0 @@ -#include "tools/select.h" - -#include -#include -#include -#include -#include -#include - -cTBSelect::cTBSelect(void) { - Clear(); -} - -cTBSelect::~cTBSelect() { -} - -int cTBSelect::Select(uint TimeoutMs) { - struct timeval tv; - ssize_t res; - int ms; - - tv.tv_usec = (TimeoutMs % 1000) * 1000; - tv.tv_sec = TimeoutMs / 1000; - - if (TimeoutMs == 0) - return ::select(m_MaxFiled + 1, &m_Rfds, &m_Wfds, NULL, &tv); - - cTimeMs starttime; - ms = TimeoutMs; - while (ms > 0 && (res = ::select(m_MaxFiled + 1, &m_Rfds, &m_Wfds, NULL, - &tv)) == -1 && errno == EINTR) { - ms = TimeoutMs - starttime.Elapsed(); - tv.tv_usec = (ms % 1000) * 1000; - tv.tv_sec = ms / 1000; - } - if (ms <= 0) { - errno = ETIMEDOUT; - return -1; - } - return res; -} - -int cTBSelect::Select(void) { - ssize_t res; - while ((res = ::select(m_MaxFiled + 1, &m_Rfds, &m_Wfds, NULL, NULL)) == -1 - && errno == EINTR) - ; - return res; -} diff --git a/tools/select.h b/tools/select.h deleted file mode 100644 index 7e873e2..0000000 --- a/tools/select.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef TOOLBOX_SELECT_H -#define TOOLBOX_SELECT_H - -#include "tools/tools.h" - -#include - -/* cTBSelect provides an interface for polling UNIX-like file descriptors. */ - -class cTBSelect { -private: - int m_MaxFiled; - - fd_set m_Rfds; - fd_set m_Wfds; - -public: - cTBSelect(void); - virtual ~cTBSelect(); - - /* Clear() resets the object for use in a new Select() call. All file - descriptors and their previous states are invalidated. */ - virtual void Clear(void); - - /* Add() adds a file descriptor to be polled in the next Select() call. - That call polls if the file is readable if Output is set to false, - writeable otherwise. */ - virtual bool Add(int Filed, bool Output = false); - - /* Select() polls all descriptors added by Add() and returns as soon as - one of those changes state (gets readable/writeable), or after - TimeoutMs milliseconds, whichever happens first. It returns the number - of filedescriptors that have changed state. On error, -1 is returned - and errno is set appropriately. */ - virtual int Select(uint TimeoutMs); - - /* Select() polls all descriptors added by Add() and returns as soon as - one of those changes state (gets readable/writeable). It returns the - number of filedescriptors that have changed state. On error, -1 is - returned and errno is set appropriately. */ - virtual int Select(void); - - /* CanRead() returns true if the descriptor has changed to readable during - the last Select() call. Otherwise false is returned. */ - virtual bool CanRead(int FileNo) const; - - /* CanWrite() returns true if the descriptor has changed to writeable - during the last Select() call. Otherwise false is returned. */ - virtual bool CanWrite(int FileNo) const; -}; - -inline void cTBSelect::Clear(void) { - FD_ZERO(&m_Rfds); - FD_ZERO(&m_Wfds); - m_MaxFiled = -1; -} - -inline bool cTBSelect::Add(int Filed, bool Output /* = false */) { - if (Filed < 0) return false; - FD_SET(Filed, Output ? &m_Wfds : &m_Rfds); - if (Filed > m_MaxFiled) m_MaxFiled = Filed; - return true; -} - -inline bool cTBSelect::CanRead(int FileNo) const { - if (FileNo < 0) return false; - return FD_ISSET(FileNo, &m_Rfds); -} - -inline bool cTBSelect::CanWrite(int FileNo) const { - if (FileNo < 0) return false; - return FD_ISSET(FileNo, &m_Wfds); -} - -#endif // TOOLBOX_SELECT_H diff --git a/tools/socket.c b/tools/socket.c deleted file mode 100644 index 3e3be65..0000000 --- a/tools/socket.c +++ /dev/null @@ -1,135 +0,0 @@ -#include "tools/socket.h" - -#include -#include -#include -#include -#include - -cTBSocket::cTBSocket(int Type) { - memset(&m_LocalAddr, 0, sizeof(m_LocalAddr)); - memset(&m_RemoteAddr, 0, sizeof(m_RemoteAddr)); - m_Type = Type; -} - -cTBSocket::~cTBSocket() { - if (IsOpen()) Close(); -} - -bool cTBSocket::Connect(const std::string &Host, unsigned int Port) { - socklen_t len; - int socket; - - if (IsOpen()) Close(); - - if ((socket = ::socket(PF_INET, m_Type, IPPROTO_IP)) == -1) - return false; - - m_LocalAddr.sin_family = AF_INET; - m_LocalAddr.sin_port = 0; - m_LocalAddr.sin_addr.s_addr = INADDR_ANY; - if (::bind(socket, (struct sockaddr*)&m_LocalAddr, sizeof(m_LocalAddr)) - == -1) - return false; - - m_RemoteAddr.sin_family = AF_INET; - m_RemoteAddr.sin_port = htons(Port); - m_RemoteAddr.sin_addr.s_addr = inet_addr(Host.c_str()); - if (::connect(socket, (struct sockaddr*)&m_RemoteAddr, - sizeof(m_RemoteAddr)) == -1) - return false; - - len = sizeof(struct sockaddr_in); - if (::getpeername(socket, (struct sockaddr*)&m_RemoteAddr, &len) == -1) - return false; - - len = sizeof(struct sockaddr_in); - if (::getsockname(socket, (struct sockaddr*)&m_LocalAddr, &len) == -1) - return false; - - return cTBSource::Open(socket); -} - -bool cTBSocket::Listen(const std::string &Ip, unsigned int Port, int BackLog) { - int val; - socklen_t len; - int socket; - - if (IsOpen()) Close(); - - if ((socket = ::socket(PF_INET, m_Type, IPPROTO_IP)) == -1) - return false; - - val = 1; - if (::setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == -1) - return false; - - m_LocalAddr.sin_family = AF_INET; - m_LocalAddr.sin_port = htons(Port); - m_LocalAddr.sin_addr.s_addr = inet_addr(Ip.c_str()); - if (::bind(socket, (struct sockaddr*)&m_LocalAddr, sizeof(m_LocalAddr)) - == -1) - return false; - - len = sizeof(struct sockaddr_in); - if (::getsockname(socket, (struct sockaddr*)&m_LocalAddr, &len) == -1) - return false; - - if (m_Type == SOCK_STREAM && ::listen(socket, BackLog) == -1) - return false; - - if (!cTBSource::Open(socket)) - return false; - - return true; -} - -bool cTBSocket::Accept(const cTBSocket &Listener) { - socklen_t addrlen; - int socket; - - if (IsOpen()) Close(); - - addrlen = sizeof(struct sockaddr_in); - if ((socket = ::accept(Listener, (struct sockaddr*)&m_RemoteAddr, - &addrlen)) == -1) - return false; - - addrlen = sizeof(struct sockaddr_in); - if (::getsockname(socket, (struct sockaddr*)&m_LocalAddr, &addrlen) == -1) - return false; - - if (!cTBSource::Open(socket)) - return false; - - return true; -} - -RETURNS(cTBSocket, cTBSocket::Accept(void) const, ret) - ret.Accept(*this); -RETURN(ret) - -bool cTBSocket::Close(void) { - bool ret = true; - - if (!IsOpen()) - ERRNUL(EBADF); - - if (::close(*this) == -1) - ret = false; - - if (!cTBSource::Close()) - ret = false; - - memset(&m_LocalAddr, 0, sizeof(m_LocalAddr)); - memset(&m_RemoteAddr, 0, sizeof(m_RemoteAddr)); - - return ret; -} - -bool cTBSocket::Shutdown(int how) { - if (!IsOpen()) - ERRNUL(EBADF); - - return ::shutdown(*this, how) != -1; -} diff --git a/tools/socket.h b/tools/socket.h deleted file mode 100644 index d1a7d62..0000000 --- a/tools/socket.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef TOOLBOX_SOCKET_H -#define TOOLBOX_SOCKET_H - -#include "tools/tools.h" -#include "tools/source.h" - -#include -#include -#include -#include - -/* cTBSocket provides a cTBSource-derived interface for input and output on - TCP/IPv4-sockets. */ - -class cTBSocket: public cTBSource { -private: - struct sockaddr_in m_LocalAddr; - struct sockaddr_in m_RemoteAddr; - - int m_Type; - -public: - cTBSocket(int Type = SOCK_STREAM); - virtual ~cTBSocket(); - - /* See cTBSource::SysRead() - Reimplemented for TCP/IPv4 sockets. */ - virtual ssize_t SysRead(void *Buffer, size_t Length) const; - - /* See cTBSource::SysWrite() - Reimplemented for TCP/IPv4 sockets. */ - virtual ssize_t SysWrite(const void *Buffer, size_t Length) const; - - /* Connect() tries to connect an available local socket to the port given - by Port of the target host given by Host in numbers-and-dots notation - (i.e. "212.43.45.21"). Returns true if the connection attempt was - successful and false otherwise, setting errno appropriately. */ - virtual bool Connect(const std::string &Host, uint Port); - - /* Shutdown() shuts down one or both ends of a socket. If called with How - set to SHUT_RD, further reads on this socket will be denied. If called - with SHUT_WR, all writes are denied. Called with SHUT_RDWR, all firther - action on this socket will be denied. Returns true on success and false - otherwise, setting errno appropriately. */ - virtual bool Shutdown(int How); - - /* Close() closes the associated socket and releases all structures. - Returns true on success and false otherwise, setting errno - appropriately. The object is in the closed state afterwards, regardless - of any errors. */ - virtual bool Close(void); - - /* Listen() listens on the local port Port for incoming connections. The - BackLog parameter defines the maximum length the queue of pending - connections may grow to. Returns true if the object is listening on - the specified port and false otherwise, setting errno appropriately. */ - virtual bool Listen(const std::string &Ip, uint Port, int BackLog); - - /* Accept() returns a newly created cTBSocket, which is connected to the - first connection request on the queue of pending connections of a - listening socket. If no connection request was pending, or if any other - error occured, the resulting cTBSocket is closed. */ - virtual cTBSocket Accept(void) const; - - /* Accept() extracts the first connection request on the queue of pending - connections of the listening socket Listener and connects it to this - object. Returns true on success and false otherwise, setting errno to - an appropriate value. */ - virtual bool Accept(const cTBSocket &Listener); - - /* LocalPort() returns the port number this socket is connected to locally. - The result is undefined for a non-open socket. */ - int LocalPort(void) const { return ntohs(m_LocalAddr.sin_port); } - - /* RemotePort() returns the port number this socket is connected to on the - remote side. The result is undefined for a non-open socket. */ - int RemotePort(void) const { return ntohs(m_RemoteAddr.sin_port); } - - /* LocalIp() returns the internet address in numbers-and-dots notation of - the interface this socket is connected to locally. This can be - "0.0.0.0" for a listening socket listening to all interfaces. If the - socket is in its closed state, the result is undefined. */ - std::string LocalIp(void) const { return inet_ntoa(m_LocalAddr.sin_addr); } - - /* RemoteIp() returns the internet address in numbers-and-dots notation of - the interface this socket is connected to on the remote side. If the - socket is in its closed state, the result is undefined. */ - std::string RemoteIp(void) const { return inet_ntoa(m_RemoteAddr.sin_addr); } - - in_addr_t LocalIpAddr(void) const { return m_LocalAddr.sin_addr.s_addr; } - in_addr_t RemoteIpAddr(void) const { return m_RemoteAddr.sin_addr.s_addr; } - - int Type(void) const { return m_Type; } -}; - -inline ssize_t cTBSocket::SysRead(void *Buffer, size_t Length) const { - if (m_Type == SOCK_DGRAM) { - socklen_t len = sizeof(m_RemoteAddr); - return ::recvfrom(*this, Buffer, Length, 0, (sockaddr*)&m_RemoteAddr, &len); - } else - return ::recv(*this, Buffer, Length, 0); -} - -inline ssize_t cTBSocket::SysWrite(const void *Buffer, size_t Length) const { - return ::send(*this, Buffer, Length, 0); -} - -#endif // TOOLBOX_SOCKET_H diff --git a/tools/source.c b/tools/source.c deleted file mode 100644 index f8751b6..0000000 --- a/tools/source.c +++ /dev/null @@ -1,169 +0,0 @@ -#include "tools/source.h" -#include "tools/select.h" - -#include -#include -#include -#include -#include - -cTBSource::cTBSource(void) { - m_BytesRead = 0; - m_BytesWritten = 0; - m_Filed = -1; -} - -bool cTBSource::Open(int Filed, bool IsUnixFd) { - if (IsOpen()) - Close(); - - m_Filed = Filed; - if (IsUnixFd && ::fcntl(m_Filed, F_SETFL, O_NONBLOCK) == -1) - return false; - - return true; -} - -cTBSource::~cTBSource() { -} - -bool cTBSource::Close(void) { - if (!IsOpen()) { - errno = EBADF; - return false; - } - - m_Filed = -1; - return true; -} - -ssize_t cTBSource::Read(void *Buffer, size_t Length) { - ssize_t res; - while ((res = SysRead(Buffer, Length)) < 0 && errno == EINTR) - errno = 0; - if (res > 0) m_BytesRead += res; - return res; -} - -ssize_t cTBSource::Write(const void *Buffer, size_t Length) { - ssize_t res; - while ((res = SysWrite(Buffer, Length)) < 0 && errno == EINTR) - errno = 0; - if (res > 0) m_BytesWritten += res; - return res; -} - -bool cTBSource::TimedWrite(const void *Buffer, size_t Length, uint TimeoutMs) { - cTBSelect sel; - int ms, offs; - - cTimeMs starttime; - ms = TimeoutMs; - offs = 0; - while (Length > 0) { - int b; - - sel.Clear(); - sel.Add(m_Filed, true); - if (sel.Select(ms) == -1) - return false; - - if (sel.CanWrite(m_Filed)) { - if ((b = Write((char*)Buffer + offs, Length)) == -1) - return false; - offs += b; - Length -= b; - } - - ms = TimeoutMs - starttime.Elapsed(); - if (ms <= 0) { - errno = ETIMEDOUT; - return false; - } - } - return true; -} - -bool cTBSource::SafeWrite(const void *Buffer, size_t Length) { - cTBSelect sel; - int offs; - - offs = 0; - while (Length > 0) { - int b; - - sel.Clear(); - sel.Add(m_Filed, true); - if (sel.Select() == -1) - return false; - - if (sel.CanWrite(m_Filed)) { - if ((b = Write((char*)Buffer + offs, Length)) == -1) - return false; - offs += b; - Length -= b; - } - - } - return true; -} - -ssize_t cTBSource::ReadUntil(void *Buffer, size_t Length, const char *Seq, - uint TimeoutMs) { - int ms; - size_t len; - cTBSelect sel; - - if ((len = m_LineBuffer.find(Seq)) != (size_t)-1) { - if (len > Length) { - errno = ENOBUFS; - return -1; - } - memcpy(Buffer, m_LineBuffer.data(), len); - m_LineBuffer.erase(0, len + strlen(Seq)); - //Dprintf("ReadUntil: Served from Linebuffer: %d, |%.*s|\n", len, len - 1, - // (char*)Buffer); - return len; - } - - cTimeMs starttime; - ms = TimeoutMs; - while (m_LineBuffer.size() < BUFSIZ) { - sel.Clear(); - sel.Add(m_Filed, false); - - if (sel.Select(ms) == -1) - return -1; - - if (sel.CanRead(m_Filed)) { - int b; - - len = m_LineBuffer.size(); - m_LineBuffer.resize(BUFSIZ); - if ((b = Read((char*)m_LineBuffer.data() + len, BUFSIZ - len)) == -1) - return -1; - m_LineBuffer.resize(len + b); - - if ((len = m_LineBuffer.find(Seq)) != (size_t)-1) { - if (len > Length) { - errno = ENOBUFS; - return -1; - } - memcpy(Buffer, m_LineBuffer.data(), len); - m_LineBuffer.erase(0, len + strlen(Seq)); - //Dprintf("ReadUntil: Served from Linebuffer: %d, |%.*s|\n", len, len - 1, - // (char*)Buffer); - return len; - } - } - - ms = TimeoutMs - starttime.Elapsed(); - if (ms <= 0) { - errno = ETIMEDOUT; - return -1; - } - } - errno = ENOBUFS; - return -1; -} - diff --git a/tools/source.h b/tools/source.h deleted file mode 100644 index 09c4bf3..0000000 --- a/tools/source.h +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef TOOLBOX_SOURCE_H -#define TOOLBOX_SOURCE_H - -#include "tools/tools.h" - -#include -#include - -/* cTBSource provides an abstract interface for input and output. It can - be used to have common access to different types of UNIX-files. */ - -class cTBSource { -private: - int m_Filed; - - size_t m_BytesRead; - size_t m_BytesWritten; - - std::string m_LineBuffer; - -public: - cTBSource(void); - virtual ~cTBSource(); - - /* SysRead() implements the low-level read on the source. It will store - data into the area pointed to by Buffer, which is at least Length - bytes in size. It will return the exact number of bytes read (which - can be fewer than requested). On error, -1 is returned, and errno - is set to an appropriate value. */ - virtual ssize_t SysRead(void *Buffer, size_t Length) const = 0; - - /* SysWrite() implements the low-level write on the source. It will write - at most Length bytes of the data pointed to by Buffer. It will return - the exact number of bytes written (which can be fewer than requested). - On error, -1 is returned, and errno is set to an appropriate value. */ - virtual ssize_t SysWrite(const void *Buffer, size_t Length) const = 0; - - /* IsOpen() returns true, if this source refers to a valid descriptor. - It is not checked whether this source is really open, so only if - opened by the appropriate Methods this function will return the - correct value */ - virtual bool IsOpen(void) const { return m_Filed != -1; } - - /* Open() associates this source with the descriptor Filed, setting it - to non-blocking mode if IsUnixFd in true. Returns true on success, - and false on error, setting errno to appropriately. - If you want to implement sources that can't be represented by UNIX - filedescriptors, you can use Filed to store any useful information - about the source. - This must be called by any derivations in an appropriate Method (like - open for files, connect for sockets). */ - virtual bool Open(int Filed, bool IsUnixFd = true); - - /* Close() resets the source to the uninitialized state (IsOpen() == false) - and must be called by any derivations after really closing the source. - Returns true on success and false on error, setting errno appropriately. - The object is in closed state afterwards, even if an error occured. */ - virtual bool Close(void); - - /* Read() reads at most Length bytes into the storage pointed to by Buffer, - which must be at least Length bytes in size, using the SysRead()- - Interface. It retries if an EINTR occurs (i.e. the low-level call was - interrupted). It returns the exact number of bytes read (which can be - fewer than requested). On error, -1 is returned, and errno is set - appropriately. */ - ssize_t Read(void *Buffer, size_t Length); - - /* Write() writes at most Length bytes from the storage pointed to by - Buffer, using the SysWrite()-Interface. It retries if EINTR occurs - (i.e. the low-level call was interrupted). It returns the exact number - of bytes written (which can be fewer than requested). On error, -1 is - returned and errno is set appropriately. */ - ssize_t Write(const void *Buffer, size_t Length); - - /* TimedWrite() tries to write Length bytes from the storage pointed to by - Buffer within the time specified by TimeoutMs, using the Write()- - Interface. On success, true is returned. On error, false is returned - and errno is set appropriately. TimedRead only works on UNIX file - descriptor sources. */ - bool TimedWrite(const void *Buffer, size_t Length, uint TimeoutMs); - - bool SafeWrite(const void *Buffer, size_t Length); - - /* ReadUntil() tries to read at most Length bytes into the storage pointed - to by Buffer, which must be at least Length bytes in size, within the - time specified by TimeoutMs, using the Read()-Interface. Reading stops - after the character sequence Seq has been read and on end-of-file. - Returns the number of bytes read (if that is equal to Length, you have - to check if the buffer ends with Seq), or -1 on error, in which case - errno is set appropriately. */ - ssize_t ReadUntil(void *Buffer, size_t Length, const char *Seq, - uint TimeoutMs); - - /* BytesRead() returns the exact number of bytes read through the Read() - method since Close() has been called on this source (or since its - creation). */ - size_t BytesRead(void) const { return m_BytesRead; } - - /* BytesWritten() returns the exact number of bytes written through the - Write() method since Close() has been called on this source (or since - its creation). */ - size_t BytesWritten(void) const { return m_BytesWritten; } - - /* operator int() returns the descriptor (or informative number) associated - with this source. */ - operator int() const { return m_Filed; } -}; - -#endif // TOOLBOX_SOURCE_H diff --git a/tools/tools.c b/tools/tools.c deleted file mode 100644 index fa813fa..0000000 --- a/tools/tools.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "tools/tools.h" - -#include -#include -#include -#include -#include - -void *operator new(size_t nSize, void *p) throw () { - return p; -} - diff --git a/tools/tools.h b/tools/tools.h deleted file mode 100644 index ab00c60..0000000 --- a/tools/tools.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef TOOLBOX_TOOLS_H -#define TOOLBOX_TOOLS_H - -//#include -//#include -#include - -//#define KILOBYTE(x) ((x)*1024) -//#define MEGABYTE(x) (KILOBYTE(x)*1024) - -//typedef unsigned int uint; -//typedef unsigned long ulong; -typedef unsigned char uchar; -//typedef unsigned short ushort; - -// Special constructor for CreateElements -void *operator new(size_t, void*) throw (); - -#ifdef TOOLBOX_DEBUG -# define ASSERT(x) if ((x)) cerr << "Warning: ASSERT failed At " << __FILE__ << ":" << __LINE__ << " ["#x"]" << endl -# define CHECK_PTR(x) if (!(x)) cerr << "Warning: Pointer is NULL At " << __FILE__ << ":" << __LINE__ << endl; -# define CHECK_NEXT_ALLOC() _checkNextAlloc() -# define DPRINT(x...) LOGi(x) -#else -# define ASSERT(x) -# define CHECK_PTR(x) -# define CHECK_NEXT_ALLOC() -# define DPRINT(x...) -#endif - -#define ERRNUL(e) {errno=e;return 0;} -#define ERRSYS(e) {errno=e;return -1;} - -/* RETURNS() and RETURN() are macros that can be used if a class object is - being returned. They make use of the GNU C-Compiler's named return value - feature, if available. In this case, the class object isn't returned and - copied, but the result itself is filled. - - RETURNS(ReturnType, FunctionDeclaration, Result) - ... function-body working on Result ... - RETURN(Result) - - A function like this (cXYZ is a class type): - - cXYZ myfunction(int a, char *b) { - cXYZ result; - ... something happens with result ... - return result; - } - - can be written like this: - - RETURNS(cXYZ, myfunction(int a, char *b), result) - ... something happens with result ... - RETURN(result) - - DISABLED SINCE GCC 3.x -*/ -//#ifdef __GNUC__ -//# define RETURNS(t,x,r) t x return r { -//# define RETURN(x) } -//#else -# define RETURNS(t,x,r) t x { t r; -# define RETURN(x) return x; } -//#endif - -#endif // TOOLBOX_TOOLS_H -- cgit v1.2.3