summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/file.c95
-rw-r--r--tools/file.h100
-rw-r--r--tools/select.c52
-rw-r--r--tools/select.h75
-rw-r--r--tools/shared.c90
-rw-r--r--tools/shared.h65
-rw-r--r--tools/socket.c135
-rw-r--r--tools/socket.h108
-rw-r--r--tools/source.c195
-rw-r--r--tools/source.h107
-rw-r--r--tools/string.c454
-rw-r--r--tools/string.h353
-rw-r--r--tools/tools.c12
-rw-r--r--tools/tools.h67
14 files changed, 1908 insertions, 0 deletions
diff --git a/tools/file.c b/tools/file.c
new file mode 100644
index 0000000..2283500
--- /dev/null
+++ b/tools/file.c
@@ -0,0 +1,95 @@
+#include "tools/file.h"
+
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+cTBFile::cTBFile(void) {
+}
+
+cTBFile::~cTBFile() {
+ Close();
+}
+
+bool cTBFile::Open(const cTBString &Filename, int Mode, mode_t Attribs) {
+ int filed;
+
+ if (IsOpen()) Close();
+
+ if ((filed = ::open(Filename, Mode, Attribs)) == -1)
+ return false;
+
+ if (!cTBSource::Open(filed))
+ return false;
+
+ m_Filename = Filename;
+ m_Anonymous = false;
+ return true;
+}
+
+bool cTBFile::Open(uint Fileno) {
+ if (IsOpen()) Close();
+
+ if (!cTBSource::Open(Fileno))
+ return false;
+
+ m_Filename.Format("<&%d>", Fileno);
+ m_Anonymous = true;
+ return true;
+}
+
+bool cTBFile::Close(void) {
+ bool ret = true;
+
+ if (!IsOpen())
+ ERRNUL(EBADF);
+
+ if (::close(*this) == -1)
+ ret = false;
+
+ if (!cTBSource::Close())
+ ret = false;
+
+ m_Filename.Clear();
+ return ret;
+}
+
+bool cTBFile::Unlink(void) const {
+ if (m_Filename.IsNull())
+ ERRNUL(ENOENT);
+
+ if (!IsOpen())
+ ERRNUL(EBADF);
+
+ if (m_Anonymous)
+ ERRNUL(EINVAL);
+
+ return cTBFile::Unlink(m_Filename);
+}
+
+bool cTBFile::Unlink(const cTBString &Filename) {
+ return (::unlink(Filename) != -1);
+}
+
+ssize_t cTBFile::Size(void) const {
+ struct stat buf;
+
+ if (!IsOpen())
+ ERRSYS(EBADF);
+
+ if (fstat(*this, &buf) == -1)
+ return -1;
+
+ return buf.st_size;
+}
+
+ssize_t cTBFile::Size(const cTBString &Filename) {
+ struct stat buf;
+
+ if (stat(Filename, &buf) == -1)
+ return -1;
+
+ return buf.st_size;
+}
diff --git a/tools/file.h b/tools/file.h
new file mode 100644
index 0000000..de63e74
--- /dev/null
+++ b/tools/file.h
@@ -0,0 +1,100 @@
+#ifndef TOOLBOX_FILE_H
+#define TOOLBOX_FILE_H
+
+#include "tools/tools.h"
+#include "tools/source.h"
+#include "tools/string.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* cTBFile provides a cTBSource-derived interface for input and output on UNIX
+ files. */
+
+class cTBFile: public cTBSource {
+private:
+ bool m_Anonymous;
+ cTBString m_Filename;
+
+ /* Unhide and forbid baseclass method */
+ virtual bool Open(int Fd, bool IsUnixFd = false) { return false; }
+
+public:
+ cTBFile(void);
+ virtual ~cTBFile();
+
+ /* enum eFileType represents the modes a file can be opened with. The full
+ open mode is one of the first three, maybe or'ed with one of the others.
+ */
+ enum eFileType {
+ ReadOnly = O_RDONLY,
+ WriteOnly = O_WRONLY,
+ ReadWrite = O_RDWR,
+
+ Create = O_CREAT,
+ Exclude = O_EXCL,
+ Truncate = O_TRUNC,
+ Append = O_APPEND
+ };
+
+ /* See cTBSource::SysRead()
+ Reimplemented for UNIX files. */
+ virtual ssize_t SysRead(void *Buffer, size_t Length) const;
+
+ /* See cTBSource::SysWrite()
+ Reimplemented for UNIX files. */
+ virtual ssize_t SysWrite(const void *Buffer, size_t Length) const;
+
+ /* Open() opens the file referred to by Filename according to the given
+ Mode. If the file is created, it receives the attributes given by
+ Attribs, defaulting to rw-------. Returns true on success and false on
+ error, setting errno appropriately. */
+ virtual bool Open(const cTBString &Filename, int Mode,
+ mode_t Attribs = S_IRUSR + S_IWUSR);
+
+ /* Open() associates this file object with Fileno. Fileno must refer to a
+ previously opened file descriptor, which will be set non-blocking by
+ this call. If successful, true is returned, false otherwise and errno
+ is set appropriately. */
+ virtual bool Open(uint Fileno);
+
+ /* Close() closes the associated file descriptor and releases all
+ structures. Returns true on success and false otherwise, setting errno
+ appropriately. The object is in the closed state afterwards, even if
+ an error occured. */
+ virtual bool Close(void);
+
+ /* Unlink() unlinks (deletes) the associated file from the underlying
+ filesystem. Returns true on success and false otherwise, setting errno
+ appropriately. The file must be opened by filename to use this. */
+ virtual bool Unlink(void) const;
+
+ /* Unlink() unlinks (deletes) the file referred to by Filename from the
+ underlying filesystem. Returns true on success and false otherwise,
+ setting errno appropriately. */
+ static bool Unlink(const cTBString &Filename);
+
+ /* Size() returns the current size of the associated file. Returns the
+ exact size of the file in bytes. Returns -1 on error, setting errno to
+ an appropriate value. */
+ virtual ssize_t Size(void) const;
+
+ /* Size() returns the current size of the file referred to by Filename.
+ Symbolic links are followed (the size of the link-target is returned).
+ Returns the exact size of the file in bytes. Returns -1 on error,
+ setting errno to an appropriate value. */
+ static ssize_t Size(const cTBString &Filename);
+};
+
+inline ssize_t cTBFile::SysRead(void *Buffer, size_t Length) const {
+ return ::read(*this, Buffer, Length);
+}
+
+inline ssize_t cTBFile::SysWrite(const void *Buffer, size_t Length) const {
+ return ::write(*this, Buffer, Length);
+}
+
+
+#endif // TOOLBOX_FILE_H
diff --git a/tools/select.c b/tools/select.c
new file mode 100644
index 0000000..77229c8
--- /dev/null
+++ b/tools/select.c
@@ -0,0 +1,52 @@
+#include "tools/select.h"
+
+#include <vdr/tools.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+
+cTBSelect::cTBSelect(void) {
+ Clear();
+}
+
+cTBSelect::~cTBSelect() {
+}
+
+int cTBSelect::Select(uint TimeoutMs) {
+ struct timeval tv;
+ time_t st, et;
+ 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);
+
+ st = time_ms();
+ ms = TimeoutMs;
+ while (ms > 0 && (res = ::select(m_MaxFiled + 1, &m_Rfds, &m_Wfds, NULL,
+ &tv)) == -1 && errno == EINTR) {
+ et = time_ms();
+ ms -= et - st;
+ tv.tv_usec = (ms % 1000) * 1000;
+ tv.tv_sec = ms / 1000;
+ st = et;
+ }
+ 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
new file mode 100644
index 0000000..7e873e2
--- /dev/null
+++ b/tools/select.h
@@ -0,0 +1,75 @@
+#ifndef TOOLBOX_SELECT_H
+#define TOOLBOX_SELECT_H
+
+#include "tools/tools.h"
+
+#include <sys/types.h>
+
+/* 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/shared.c b/tools/shared.c
new file mode 100644
index 0000000..ef20969
--- /dev/null
+++ b/tools/shared.c
@@ -0,0 +1,90 @@
+#include "tools/shared.h"
+
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+cSharedData *cSharedData::Construct (size_t Length) {
+ size_t reallength = sizeof(cSharedData) + Length;
+ cSharedData *ret = (cSharedData*)new char[reallength];
+
+ ret->m_Length = Length;
+ ret->m_NumRefs = 0;
+ return ret;
+}
+
+cTBShared::cTBShared(void) {
+ m_Buffer = NULL;
+}
+
+cTBShared::cTBShared (const cTBShared &src) {
+ m_Buffer = src.m_Buffer;
+ if (m_Buffer)
+ ++*m_Buffer;
+}
+
+cTBShared::~cTBShared () {
+ if (m_Buffer)
+ Release();
+}
+
+void cTBShared::Clear () {
+ if (m_Buffer)
+ Release();
+ m_Buffer = 0;
+}
+
+void cTBShared::Set (const cTBShared &src) {
+ if (m_Buffer)
+ Release();
+
+ m_Buffer = src.m_Buffer;
+ if (m_Buffer)
+ ++*m_Buffer;
+}
+
+void cTBShared::Release () {
+ CHECK_PTR(m_Buffer);
+
+ if (--*m_Buffer == 0)
+ delete[] (char*)m_Buffer;
+
+ m_Buffer = 0;
+}
+
+void cTBShared::Release(uint newsize) {
+ CHECK_PTR(m_Buffer);
+
+ Allocate(newsize, true);
+}
+
+void cTBShared::Exclusive () {
+ CHECK_PTR(m_Buffer);
+
+ if (m_Buffer->Refs() == 1)
+ return;
+
+ cSharedData *copy = cSharedData::Construct(m_Buffer->Size());
+ memcpy(*copy, *m_Buffer, m_Buffer->Size());
+
+ Release();
+
+ m_Buffer = copy;
+ ++*m_Buffer;
+}
+
+void cTBShared::Allocate (size_t len, bool keep /* = false */) {
+ if (m_Buffer && (m_Buffer->Refs() == 1) && (m_Buffer->Size() == len))
+ return;
+
+ cSharedData *newBuffer = cSharedData::Construct(len);
+ if (m_Buffer) {
+ if (keep)
+ memcpy(*newBuffer, *m_Buffer, len < m_Buffer->Size() ? len : m_Buffer->Size());
+
+ Release();
+ }
+ m_Buffer = newBuffer;
+ ++*m_Buffer;
+}
+
diff --git a/tools/shared.h b/tools/shared.h
new file mode 100644
index 0000000..bacb708
--- /dev/null
+++ b/tools/shared.h
@@ -0,0 +1,65 @@
+#ifndef TOOLBOX_SHARED_H
+#define TOOLBOX_SHARED_H
+
+#include "tools/tools.h"
+
+struct cSharedData {
+private:
+ uint m_Length;
+ uint m_NumRefs;
+
+public:
+ static cSharedData *Construct (size_t Length);
+
+ operator char * () { return this ? (char*)(this+1) : 0; }
+
+ uint operator++ () { return ++m_NumRefs; }
+ uint operator-- () { return --m_NumRefs; }
+
+ size_t Size() const { return m_Length; }
+
+ uint Refs () const { return m_NumRefs; }
+};
+
+class cTBShared {
+private:
+ cSharedData *m_Buffer;
+
+protected:
+ void Release();
+ void Exclusive();
+ void Allocate(size_t len, bool keep = false);
+
+ char *Buffer() const { return m_Buffer ? (char*)*m_Buffer : (char*)0; }
+
+public:
+ cTBShared (void);
+ cTBShared (const cTBShared &src);
+ virtual ~cTBShared ();
+
+ virtual void Clear ();
+ virtual void Set (const cTBShared &src);
+
+ virtual char *Buffer (uint size);
+ virtual void Release (uint newsize);
+
+ cTBShared &operator= (const cTBShared &src) { Set(src); return *this; }
+
+ operator const void * () const { return m_Buffer ? (const void*)*m_Buffer : (const void*)0; }
+ operator void * () const { return m_Buffer ? (void*)*m_Buffer : (void*)0; }
+
+ operator const char * () const { return m_Buffer ? (const char*)*m_Buffer : (const char*)0; }
+
+ size_t Size() const { return m_Buffer ? m_Buffer->Size() : 0; }
+ size_t Length() const { return m_Buffer ? m_Buffer->Size() : 0; }
+
+ // friend cSource &operator>> (cSource &dest, cTBShared &str);
+};
+
+inline char *cTBShared::Buffer(uint size) {
+ if ((!m_Buffer) || (m_Buffer->Refs() > 1) || (size > m_Buffer->Size()))
+ Allocate(size, true);
+ return Buffer();
+}
+
+#endif // TOOLBOX_SHARED_H
diff --git a/tools/socket.c b/tools/socket.c
new file mode 100644
index 0000000..46d7b9a
--- /dev/null
+++ b/tools/socket.c
@@ -0,0 +1,135 @@
+#include "tools/socket.h"
+
+#include <string.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+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 cTBString &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);
+ 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 char *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);
+ 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
new file mode 100644
index 0000000..a4b06ab
--- /dev/null
+++ b/tools/socket.h
@@ -0,0 +1,108 @@
+#ifndef TOOLBOX_SOCKET_H
+#define TOOLBOX_SOCKET_H
+
+#include "tools/tools.h"
+#include "tools/source.h"
+#include "tools/string.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/* 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 cTBString &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 char *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. */
+ cTBString 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. */
+ cTBString 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
new file mode 100644
index 0000000..91c36c8
--- /dev/null
+++ b/tools/source.c
@@ -0,0 +1,195 @@
+#include "tools/source.h"
+#include "tools/select.h"
+#include "common.h"
+
+#include <vdr/tools.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+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;
+ time_t st;
+ int ms, offs;
+
+ st = time_ms();
+ 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 -= time_ms() - st;
+ if (ms <= 0) {
+ errno = ETIMEDOUT;
+ return false;
+ }
+ }
+ return true;
+}
+
+ssize_t cTBSource::ReadUntil(void *Buffer, size_t Length, const char *Seq,
+ uint TimeoutMs) {
+ char *offs;
+ time_t st;
+ int seqlen, ms;
+ size_t olen;
+ cTBSelect sel;
+
+ seqlen = strlen(Seq);
+ if ((offs = (char*)memmem(m_LineBuffer, m_LineBuffer.Length(), Seq, seqlen))){
+ olen = offs - m_LineBuffer;
+ if (olen >= Length) {
+ errno = ENOBUFS;
+ return -1;
+ }
+ memcpy(Buffer, m_LineBuffer, olen);
+ m_LineBuffer = m_LineBuffer.Mid(olen + seqlen);
+ Dprintf("ReadUntil: Served from Linebuffer: %d, |%.*s|\n", olen, olen - 1,
+ (char*)Buffer);
+ return olen;
+ }
+
+ st = time_ms();
+ ms = TimeoutMs;
+ while (m_LineBuffer.Length() < BUFSIZ) {
+ int b;
+
+ sel.Clear();
+ sel.Add(m_Filed, false);
+
+ if (sel.Select(ms) == -1)
+ return -1;
+
+ if (sel.CanRead(m_Filed)) {
+ offs = m_LineBuffer.Buffer(BUFSIZ);
+ if ((b = Read(offs + m_LineBuffer.Length(), BUFSIZ
+ - m_LineBuffer.Length())) == -1)
+ return -1;
+
+ m_LineBuffer.Release(m_LineBuffer.Length() + b);
+ if ((offs = (char*)memmem(m_LineBuffer, m_LineBuffer.Length(), Seq,
+ seqlen))) {
+ olen = offs - m_LineBuffer;
+ if (olen >= Length) {
+ errno = ENOBUFS;
+ return -1;
+ }
+ memcpy(Buffer, m_LineBuffer, olen);
+ m_LineBuffer = m_LineBuffer.Mid(olen + seqlen, m_LineBuffer.Length()
+ - olen - seqlen);
+ Dprintf("ReadUntil: Served after Read: %d, |%.*s|\n", olen, olen-1,
+ (char*)Buffer);
+ return olen;
+ }
+ }
+
+ ms -= time_ms() - st;
+ if (ms <= 0) {
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ }
+ errno = ENOBUFS;
+ return -1;
+
+
+
+/*
+ cTBSelect sel;
+ time_t st, et;
+ int ms, seqlen, offs;
+
+ seqlen = strlen(Seq);
+ st = time_ms();
+ ms = TimeoutMs;
+ offs = 0;
+ while (Length > 0) {
+ int b;
+
+ sel.Clear();
+ sel.Add(m_Filed, false);
+ if (sel.Select(ms) == -1)
+ return -1;
+
+ if (sel.CanRead(m_Filed)) {
+ if ((b = Read((char*)Buffer + offs, Length)) == -1)
+ return -1;
+
+ offs += b;
+ Length -= b;
+
+ if (memmem(Buffer, offs, Seq, seqlen) != NULL)
+ return offs;
+ }
+
+ et = time_ms();
+ ms -= et - st;
+ if (ms <= 0) {
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ }
+ errno = ENOBUFS;
+ return -1;
+*/
+}
+
diff --git a/tools/source.h b/tools/source.h
new file mode 100644
index 0000000..09536bc
--- /dev/null
+++ b/tools/source.h
@@ -0,0 +1,107 @@
+#ifndef TOOLBOX_SOURCE_H
+#define TOOLBOX_SOURCE_H
+
+#include "tools/tools.h"
+#include "tools/string.h"
+
+#include <sys/types.h>
+
+/* 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;
+
+ cTBString 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);
+
+ /* 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/string.c b/tools/string.c
new file mode 100644
index 0000000..0897ece
--- /dev/null
+++ b/tools/string.c
@@ -0,0 +1,454 @@
+#include "tools/string.h"
+#ifdef TOOLBOX_REGEX
+# include "tools/regex.h"
+#endif
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <limits.h>
+#include <math.h>
+#include <errno.h>
+
+const cTBString cTBString::Null;
+
+cTBString::cTBString():
+ cTBShared(),
+ m_StringLen(0) {
+}
+
+cTBString::cTBString(const cTBString &src):
+ cTBShared(src),
+ m_StringLen(src.m_StringLen) {
+}
+
+cTBString::cTBString(const char *src) {
+ Set(src);
+}
+
+cTBString::cTBString(const uchar *src) {
+ Set(src);
+}
+
+cTBString::cTBString(char src) {
+ Set(src);
+}
+
+cTBString::~cTBString () {
+}
+
+void cTBString::Release(uint newsize) {
+ m_StringLen = newsize;
+ cTBShared::Release(m_StringLen + 1);
+ Buffer()[m_StringLen] = 0;
+}
+
+void cTBString::Clear() {
+ cTBShared::Clear();
+ m_StringLen = 0;
+}
+
+void cTBString::Set(const cTBString &String) {
+ cTBShared::Set(String);
+ m_StringLen = String.m_StringLen;
+}
+
+void cTBString::Set (const char *String) {
+ m_StringLen = strlen(String);
+ Allocate(m_StringLen + 1);
+
+ memcpy(Buffer(), String, m_StringLen);
+ Buffer()[m_StringLen] = 0;
+}
+
+void cTBString::Set (const uchar *String) {
+ Set((const char*)String);
+}
+
+void cTBString::Set (char Character) {
+ m_StringLen = 1;
+ Allocate(m_StringLen + 1);
+
+ Buffer()[0] = Character;
+ Buffer()[1] = 0;
+}
+
+void cTBString::Fill(char Character, int Length) {
+ if (Length != -1) {
+ m_StringLen = Length;
+ Allocate(m_StringLen + 1);
+ }
+ memset(Buffer(), Character, m_StringLen);
+ Buffer()[m_StringLen] = 0;
+}
+
+void cTBString::Append(const cTBString &src) {
+ Allocate(m_StringLen + src.m_StringLen + 1, true);
+
+ memcpy(Buffer() + m_StringLen, src.Buffer(), src.m_StringLen);
+ m_StringLen += src.m_StringLen;
+ Buffer()[m_StringLen] = 0;
+}
+
+void cTBString::Append(const char *src) {
+ uint len = strlen(src);
+ Allocate(m_StringLen + len + 1, true);
+
+ memcpy(Buffer() + m_StringLen, src, len);
+ m_StringLen += len;
+ Buffer()[m_StringLen] = 0;
+}
+
+void cTBString::Append(char src) {
+ Allocate(m_StringLen + 2, true);
+
+ Buffer()[m_StringLen] = src;
+ ++m_StringLen;
+ Buffer()[m_StringLen] = 0;
+}
+
+void cTBString::Prepend(const cTBString &src) {
+ Allocate(m_StringLen + src.m_StringLen + 1, true);
+
+ memmove(Buffer() + src.m_StringLen, Buffer(), m_StringLen);
+ memcpy(Buffer(), src.Buffer(), src.m_StringLen);
+ m_StringLen += src.m_StringLen;
+ Buffer()[m_StringLen] = 0;
+}
+
+void cTBString::Prepend(const char *src) {
+ uint len = strlen(src);
+ Allocate(m_StringLen + len + 1, true);
+
+ memmove(Buffer() + len, Buffer(), m_StringLen);
+ memcpy(Buffer(), src, len);
+ m_StringLen += len;
+ Buffer()[m_StringLen] = 0;
+}
+
+void cTBString::Prepend(char src) {
+ Allocate(m_StringLen + 2, true);
+
+ memmove(Buffer() + 1, Buffer(), m_StringLen);
+ Buffer()[0] = src;
+ Buffer()[++m_StringLen] = 0;
+}
+
+void cTBString::Insert(uint Index, const cTBString &String) {
+ Allocate(m_StringLen + String.m_StringLen + 1, true);
+
+ memmove(Buffer() + Index + String.m_StringLen, Buffer() + Index, m_StringLen - Index);
+ memcpy(Buffer() + Index, String.Buffer(), String.m_StringLen);
+ m_StringLen += String.m_StringLen;
+ Buffer()[m_StringLen] = 0;
+}
+
+void cTBString::Insert(uint Index, const char *String) {
+ uint len = strlen(String);
+ Allocate(m_StringLen + len + 1, true);
+
+ memmove(Buffer() + Index + len, Buffer() + Index, m_StringLen - Index);
+ memcpy(Buffer() + Index, String, len);
+ m_StringLen += len;
+ Buffer()[m_StringLen] = 0;
+}
+
+void cTBString::Insert(uint Index, char Character) {
+ Allocate(m_StringLen + 2, true);
+
+ memmove(Buffer() + Index + 1, Buffer() + Index, m_StringLen - Index);
+ Buffer()[Index] = Character;
+ Buffer()[++m_StringLen] = 0;
+}
+
+RETURNS(cTBString, cTBString::Left(uint count) const, ret)
+ if (count > m_StringLen)
+ count = m_StringLen;
+
+ ret.Allocate(count + 1);
+ memcpy(ret.Buffer(), Buffer(), count);
+ ret.Buffer()[count] = 0;
+ ret.m_StringLen = count;
+RETURN(ret)
+
+RETURNS(cTBString, cTBString::Right(uint count) const, ret)
+ if (count > m_StringLen)
+ count = m_StringLen;
+
+ ret.Allocate(count + 1);
+ memcpy(ret.Buffer(), Buffer() + m_StringLen - count, count);
+ ret.Buffer()[count] = 0;
+ ret.m_StringLen = count;
+RETURN(ret)
+
+RETURNS(cTBString, cTBString::Mid(int idx, int count) const, ret)
+ if (idx < 0)
+ idx = m_StringLen + idx;
+
+ if ((count < 0) || (count > (int)m_StringLen - idx))
+ count = m_StringLen - idx;
+
+ ret.Allocate(count + 1);
+ memcpy(ret.Buffer(), Buffer() + idx, count);
+ ret.Buffer()[count] = 0;
+ ret.m_StringLen = count;
+RETURN(ret)
+
+int cTBString::Find (const cTBString &String, uint Offset) const {
+ if (Offset >= m_StringLen)
+ return -1;
+
+ char *pos = strstr(Buffer() + Offset, String.Buffer());
+ if (pos) return (pos - Buffer());
+ else return -1;
+}
+
+int cTBString::Find (const char *String, uint Offset) const {
+ if (Offset >= m_StringLen)
+ return -1;
+
+ char *pos = strstr(Buffer() + Offset, String);
+ if (pos) return (pos - Buffer());
+ else return -1;
+}
+
+int cTBString::Find (char Character, uint Offset) const {
+ if (Offset >= m_StringLen)
+ return -1;
+
+ char *pos = strchr(Buffer() + Offset, Character);
+ if (pos) return (pos - Buffer());
+ else return -1;
+}
+
+#ifdef TOOLBOX_REGEX
+bool cTBString::Find (cTBRegEx &Regex, uint Offset) const {
+ return Regex.Match(Buffer(), Offset);
+}
+#endif
+
+void cTBString::Format (const char *fmt, ...) {
+ int n, size = 128;
+ va_list ap;
+
+ char *buf = Buffer(size);
+
+ while (1) {
+ va_start(ap, fmt);
+ n = vsnprintf(buf, size, fmt, ap);
+ va_end(ap);
+
+ if ((n > -1) && (n < size))
+ break;
+
+ if (n > -1)
+ size = n + 1;
+ else
+ size *= 2;
+
+ buf = Buffer(size);
+ }
+ Release(n);
+}
+
+void cTBString::Format(const cTBString &fmt, ...) {
+ int n, size = 128;
+ va_list ap;
+
+ char *buf = Buffer(size);
+
+ while (1) {
+ va_start(ap, &fmt);
+ n = vsnprintf(buf, size, fmt, ap);
+ va_end(ap);
+
+ if ((n > -1) && (n < size))
+ break;
+
+ if (n > -1)
+ size = n + 1;
+ else
+ size *= 2;
+
+ buf = Buffer(size);
+ }
+ Release(n);
+}
+
+template<cTBString::TOFUNC F>
+cTBString cTBString::ToAnything(void) const {
+ const char *src;
+ char *dest;
+ cTBString ret;
+
+ src = Buffer();
+ dest = ret.Buffer(m_StringLen + 1);
+
+ for (; src < Buffer() + m_StringLen; ++src, ++dest)
+ *dest = F(*src);
+
+ *dest = '\0';
+
+ ret.Release(m_StringLen);
+ return ret;
+}
+
+template<cTBString::ISFUNC F>
+bool cTBString::IsAnything(void) const {
+ const char *ptr = Buffer();
+
+ for (; ptr < Buffer() + m_StringLen; ++ptr)
+ if (!F(*ptr)) return false;
+
+ return true;
+}
+
+short cTBString::ToShort(bool *Ok) const {
+ long ret;
+ char *endptr;
+ bool res = false;
+
+ ret = strtol(Buffer(), &endptr, 0);
+
+ if (!IsEmpty() && *endptr == '\0' && ret >= SHRT_MIN && ret <= SHRT_MAX)
+ res = true;
+
+ if (Ok) *Ok = res;
+ return (short)ret;
+}
+
+ushort cTBString::ToUShort(bool *Ok) const {
+ ulong ret;
+ char *endptr;
+ bool res = false;
+
+ ret = strtoul(Buffer(), &endptr, 0);
+
+ if (!IsEmpty() && *endptr == '\0' && ret <= USHRT_MAX)
+ res = true;
+
+ if (Ok) *Ok = res;
+ return (ushort)ret;
+}
+
+int cTBString::ToInt(bool *Ok) const {
+ long ret;
+ char *endptr;
+ bool res = false;
+
+ ret = strtol(Buffer(), &endptr, 0);
+
+ if (!IsEmpty() && *endptr == '\0' && ret >= INT_MIN && ret <= INT_MAX)
+ res = true;
+
+ if (Ok) *Ok = res;
+ return (int)ret;
+}
+
+uint cTBString::ToUInt(bool *Ok) const {
+ ulong ret;
+ char *endptr;
+ bool res = false;
+
+ ret = strtoul(Buffer(), &endptr, 0);
+
+ if (!IsEmpty() && *endptr == '\0' && ret <= UINT_MAX)
+ res = true;
+
+ if (Ok) *Ok = res;
+ return (uint)ret;
+}
+
+long cTBString::ToLong(bool *Ok) const {
+ long ret;
+ char *endptr;
+ bool res = false;
+
+ errno = 0;
+ ret = strtol(Buffer(), &endptr, 0);
+
+ if (!IsEmpty() && *endptr == '\0' && errno != ERANGE)
+ res = true;
+
+ if (Ok) *Ok = res;
+ return (long)ret;
+}
+
+ulong cTBString::ToULong(bool *Ok) const {
+ ulong ret;
+ char *endptr;
+ bool res = false;
+
+ errno = 0;
+ ret = strtoul(Buffer(), &endptr, 0);
+
+ if (!IsEmpty() && *endptr == '\0' && errno != ERANGE)
+ res = true;
+
+ if (Ok) *Ok = res;
+ return (ulong)ret;
+}
+
+float cTBString::ToFloat(bool *Ok) const {
+ double ret;
+ char *endptr;
+ bool res = false;
+
+ ret = strtod(Buffer(), &endptr);
+
+ if (!IsEmpty() && *endptr == '\0' && errno != ERANGE)
+ res = true;
+
+ if (Ok) *Ok = res;
+ return (float)ret;
+}
+
+double cTBString::ToDouble(bool *Ok) const {
+ double ret;
+ char *endptr;
+ bool res = false;
+
+ errno = 0;
+ ret = strtol(Buffer(), &endptr, 0);
+
+ if (!IsEmpty() && *endptr == '\0' && errno != ERANGE)
+ res = true;
+
+ if (Ok) *Ok = res;
+ return (double)ret;
+}
+
+RETURNS(cTBString, cTBString::Number(short Num), ret)
+ ret.Format("%hd", Num);
+RETURN(ret)
+
+RETURNS(cTBString, cTBString::Number(ushort Num), ret)
+ ret.Format("%hu", Num);
+RETURN(ret)
+
+RETURNS(cTBString, cTBString::Number(int Num), ret)
+ ret.Format("%d", Num);
+RETURN(ret)
+
+RETURNS(cTBString, cTBString::Number(uint Num), ret)
+ ret.Format("%u", Num);
+RETURN(ret)
+
+RETURNS(cTBString, cTBString::Number(long Num), ret)
+ ret.Format("%ld", Num);
+RETURN(ret)
+
+RETURNS(cTBString, cTBString::Number(ulong Num), ret)
+ ret.Format("%lu", Num);
+RETURN(ret)
+
+RETURNS(cTBString, cTBString::Number(float Num), ret)
+ ret.Format("%f", Num);
+RETURN(ret)
+
+RETURNS(cTBString, cTBString::Number(double Num), ret)
+ ret.Format("%f", Num);
+RETURN(ret)
+
diff --git a/tools/string.h b/tools/string.h
new file mode 100644
index 0000000..2e81929
--- /dev/null
+++ b/tools/string.h
@@ -0,0 +1,353 @@
+#ifndef TOOLBOX_STRING_H
+#define TOOLBOX_STRING_H
+
+#include "tools/tools.h"
+#include "tools/shared.h"
+//#include "tools/source.h"
+
+#include <ctype.h>
+#include <stddef.h>
+#include <string.h>
+
+#ifdef TOOLBOX_REGEX
+class cTBRegEx;
+#endif
+
+class cTBString: public cTBShared {
+private:
+ uint m_StringLen;
+
+ /* Unhide and forbid baseclass method */
+ virtual void Set (const cTBShared &src) {}
+
+public:
+ cTBString ();
+ cTBString (const cTBString &src);
+ cTBString (const uchar *src);
+ cTBString (const char *src);
+ cTBString (char src);
+ virtual ~cTBString ();
+
+ static const cTBString Null;
+
+ void Clear ();
+ void Set (const cTBString &String);
+ void Set (const uchar *String);
+ void Set (const char *String);
+ void Set (char Character);
+
+ void Fill (char Character, int Length = -1);
+
+ void Release (uint newsize);
+
+ cTBString &operator= (const cTBString &src) { Set(src); return *this; }
+ cTBString &operator= (const char *src) { Set(src); return *this; }
+ cTBString &operator= (char src) { Set(src); return *this; }
+
+ void Append (const cTBString &src);
+ void Append (const char *src);
+ void Append (char src);
+
+ friend cTBString operator+ (const cTBString &a, const cTBString &b);
+ friend cTBString operator+ (const cTBString &a, const char *b);
+ friend cTBString operator+ (const char *a, const cTBString &b);
+ friend cTBString operator+ (const cTBString &a, char b);
+ friend cTBString operator+ (char a, const cTBString &b);
+
+ friend cTBString &operator+= (cTBString &a, const cTBString &b);
+ friend cTBString &operator+= (cTBString &a, const char *b);
+ friend cTBString &operator+= (cTBString &a, char b);
+
+ void Prepend (const cTBString &src);
+ void Prepend (const char *src);
+ void Prepend (char src);
+
+ void Insert (uint Index, const cTBString &src);
+ void Insert (uint Index, const char *src);
+ void Insert (uint Index, char src);
+
+ char At (uint i) const;
+ char operator[] (int i) const { return At((uint)i); }
+
+ char &At (uint i);
+ char &operator[] (int i) { return At(i); }
+
+ cTBString Left (uint Count) const;
+ cTBString Right (uint Count) const;
+ cTBString Mid (int idx, int Count = -1) const;
+
+ int Find (const cTBString &String, uint Offset = 0) const;
+ int Find (const char *String, uint Offset = 0) const;
+ int Find (char Character, uint Offset = 0) const;
+#ifdef TOOLBOX_REGEX
+ bool Find (cTBRegEx &Regex, uint Offset = 0) const;
+#endif
+
+ void Format (const char *fmt, ...)
+#if defined(__GNUC__)
+ __attribute__ ((format (printf, 2, 3)))
+#endif
+ ;
+ void Format (const cTBString &fmt, ...);
+
+ typedef int(*TOFUNC)(int);
+ template<TOFUNC F> cTBString ToAnything(void) const;
+
+ cTBString ToUpper (void) const { return ToAnything<toupper>(); }
+ cTBString ToLower (void) const { return ToAnything<tolower>(); }
+
+ typedef int(*ISFUNC)(int);
+ template<ISFUNC F> bool IsAnything(void) const;
+
+ bool IsAlnum(void) const { return IsAnything<isalnum>(); }
+ bool IsAlpha(void) const { return IsAnything<isalpha>(); }
+ bool IsAscii(void) const { return IsAnything<isascii>(); }
+ bool IsCntrl(void) const { return IsAnything<iscntrl>(); }
+ bool IsDigit(void) const { return IsAnything<isdigit>(); }
+ bool IsGraph(void) const { return IsAnything<isgraph>(); }
+ bool IsLower(void) const { return IsAnything<islower>(); }
+ bool IsPrint(void) const { return IsAnything<isprint>(); }
+ bool IsPunct(void) const { return IsAnything<ispunct>(); }
+ bool IsSpace(void) const { return IsAnything<isspace>(); }
+ bool IsUpper(void) const { return IsAnything<isupper>(); }
+ bool IsXdigit(void) const { return IsAnything<isxdigit>(); }
+
+#if defined(_GNU_SOURCE)
+ bool IsBlank(void) const { return IsAnything<isblank>(); }
+#endif
+
+ uint Length (void) const { return m_StringLen; }
+ bool IsEmpty (void) const { return m_StringLen == 0; }
+ bool IsNull (void) const { return Buffer() == 0; }
+
+ short ToShort(bool *Ok = NULL) const;
+ ushort ToUShort(bool *Ok = NULL) const;
+ int ToInt(bool *Ok = NULL) const;
+ uint ToUInt(bool *Ok = NULL) const;
+ long ToLong(bool *Ok = NULL) const;
+ ulong ToULong(bool *Ok = NULL) const;
+ float ToFloat(bool *Ok = NULL) const;
+ double ToDouble(bool *Ok = NULL) const;
+
+ static cTBString Number(short Num);
+ static cTBString Number(ushort Num);
+ static cTBString Number(int Num);
+ static cTBString Number(uint Num);
+ static cTBString Number(long Num);
+ static cTBString Number(ulong Num);
+ static cTBString Number(float Num);
+ static cTBString Number(double Num);
+
+ friend bool operator== (const cTBString &str1, const cTBString &str2);
+ friend bool operator== (const cTBString &str1, const char *str2);
+ friend bool operator== (const char *str1, const cTBString &str2);
+
+ friend bool operator!= (const cTBString &str1, const cTBString &str2);
+ friend bool operator!= (const cTBString &str1, const char *str2);
+ friend bool operator!= (const char *str1, const cTBString &str2);
+
+ friend bool operator< (const cTBString &str1, const cTBString &str2);
+ friend bool operator< (const cTBString &str1, const char *str2);
+ friend bool operator< (const char *str1, const cTBString &str2);
+
+ friend bool operator> (const cTBString &str1, const cTBString &str2);
+ friend bool operator> (const cTBString &str1, const char *str2);
+ friend bool operator> (const char *str1, const cTBString &str2);
+
+ friend bool operator<= (const cTBString &str1, const cTBString &str2);
+ friend bool operator<= (const cTBString &str1, const char *str2);
+ friend bool operator<= (const char *str1, const cTBString &str2);
+
+ friend bool operator>= (const cTBString &str1, const cTBString &str2);
+ friend bool operator>= (const cTBString &str1, const char *str2);
+ friend bool operator>= (const char *str1, const cTBString &str2);
+};
+
+inline char cTBString::At(uint idx) const {
+ ASSERT(idx >= m_StringLen);
+ return Buffer() ? Buffer()[idx] : 0;
+}
+
+inline char &cTBString::At(uint idx) {
+ static char null = 0;
+ ASSERT(idx >= m_StringLen);
+ if (Buffer()) {
+ Exclusive();
+ return Buffer()[idx];
+ } else
+ return (null = 0);
+}
+
+inline
+RETURNS(cTBString, operator+(const cTBString &a, const cTBString &b), ret(a))
+ ret.Append(b);
+RETURN(ret)
+
+inline
+RETURNS(cTBString, operator+ (const cTBString &a, const char *b), ret(a))
+ ret.Append(b);
+RETURN(ret)
+
+inline
+RETURNS(cTBString, operator+ (const char *a, const cTBString &b), ret(a))
+ ret.Append(b);
+RETURN(ret)
+
+inline
+RETURNS(cTBString, operator+ (const cTBString &a, char b), ret(a))
+ ret.Append(b);
+RETURN(ret)
+
+inline
+RETURNS(cTBString, operator+ (char a, const cTBString &b), ret(a))
+ ret.Append(b);
+RETURN(ret)
+
+inline cTBString &operator+= (cTBString &a, const cTBString &b) {
+ a.Append(b);
+ return a;
+}
+
+inline cTBString &operator+= (cTBString &a, const char *b) {
+ a.Append(b);
+ return a;
+}
+
+inline cTBString &operator+= (cTBString &a, char b) {
+ a.Append(b);
+ return a;
+}
+
+inline bool operator== (const cTBString &str1, const cTBString &str2) {
+ if (str1.Length() != str2.Length())
+ return false;
+ return memcmp(str1.Buffer(), str2.Buffer(), str1.Length()) == 0;
+}
+
+inline bool operator== (const cTBString &str1, const char *str2) {
+ uint len = strlen(str2);
+ if (str1.Length() != len)
+ return false;
+ return memcmp(str1.Buffer(), str2, len) == 0;
+}
+
+inline bool operator== (const char *str1, const cTBString &str2) {
+ uint len = strlen(str1);
+ if (len != str2.Length())
+ return false;
+ return memcmp(str1, str2.Buffer(), len) == 0;
+}
+
+inline bool operator!= (const cTBString &str1, const cTBString &str2) {
+ if (str1.Length() != str2.Length())
+ return true;
+ return memcmp(str1.Buffer(), str2.Buffer(), str1.Length()) != 0;
+}
+
+inline bool operator!= (const cTBString &str1, const char *str2) {
+ uint len = strlen(str2);
+ if (str1.Length() != len)
+ return true;
+ return memcmp(str1.Buffer(), str2, len) != 0;
+}
+
+inline bool operator!= (const char *str1, const cTBString &str2) {
+ uint len = strlen(str1);
+ if (len != str2.Length())
+ return true;
+ return memcmp(str1, str2.Buffer(), len) != 0;
+}
+
+inline bool operator< (const cTBString &str1, const cTBString &str2) {
+ int ret = memcmp(str1.Buffer(), str2.Buffer(), str1.Length() < str2.Length() ? str1.Length() : str2.Length());
+ if ((ret < 0) || ((ret == 0) && (str1.Length() < str2.Length())))
+ return true;
+ return false;
+}
+
+inline bool operator< (const cTBString &str1, const char *str2) {
+ uint len = strlen(str2);
+ int ret = memcmp(str1.Buffer(), str2, str1.Length() < len ? str1.Length() : len);
+ if ((ret < 0) || ((ret == 0) && (str1.Length() < len)))
+ return true;
+ return false;
+}
+
+inline bool operator< (const char *str1, const cTBString &str2) {
+ uint len = strlen(str1);
+ int ret = memcmp(str1, str2.Buffer(), len < str2.Length() ? len : str2.Length());
+ if ((ret < 0) || ((ret == 0) && (len < str2.Length())))
+ return true;
+ return false;
+}
+
+inline bool operator> (const cTBString &str1, const cTBString &str2) {
+ int ret = memcmp(str1.Buffer(), str2.Buffer(), str1.Length() < str2.Length() ? str1.Length() : str2.Length());
+ if ((ret > 0) || ((ret == 0) && (str1.Length() < str2.Length())))
+ return true;
+ return false;
+}
+
+inline bool operator> (const cTBString &str1, const char *str2) {
+ uint len = strlen(str2);
+ int ret = memcmp(str1.Buffer(), str2, str1.Length() < len ? str1.Length() : len);
+ if ((ret > 0) || ((ret == 0) && (str1.Length() < len)))
+ return true;
+ return false;
+}
+
+inline bool operator> (const char *str1, const cTBString &str2) {
+ uint len = strlen(str1);
+ int ret = memcmp(str1, str2.Buffer(), len < str2.Length() ? len : str2.Length());
+ if ((ret > 0) || ((ret == 0) && (len < str2.Length())))
+ return true;
+ return false;
+}
+
+inline bool operator<= (const cTBString &str1, const cTBString &str2) {
+ int ret = memcmp(str1.Buffer(), str2.Buffer(), str1.Length() < str2.Length() ? str1.Length() : str2.Length());
+ if ((ret < 0) || ((ret == 0) && (str1.Length() <= str2.Length())))
+ return true;
+ return false;
+}
+
+inline bool operator<= (const cTBString &str1, const char *str2) {
+ uint len = strlen(str2);
+ int ret = memcmp(str1.Buffer(), str2, str1.Length() < len ? str1.Length() : len);
+ if ((ret < 0) || ((ret == 0) && (str1.Length() <= len)))
+ return true;
+ return false;
+}
+
+inline bool operator<= (const char *str1, const cTBString &str2) {
+ uint len = strlen(str1);
+ int ret = memcmp(str1, str2.Buffer(), len < str2.Length() ? len : str2.Length());
+ if ((ret < 0) || ((ret == 0) && (len <= str2.Length())))
+ return true;
+ return false;
+}
+
+inline bool operator>= (const cTBString &str1, const cTBString &str2) {
+ int ret = memcmp(str1.Buffer(), str2.Buffer(), str1.Length() < str2.Length() ? str1.Length() : str2.Length());
+ if ((ret > 0) || ((ret == 0) && (str1.Length() >= str2.Length())))
+ return true;
+ return false;
+}
+
+inline bool operator>= (const cTBString &str1, const char *str2) {
+ uint len = strlen(str2);
+ int ret = memcmp(str1.Buffer(), str2, str1.Length() < len ? str1.Length() : len);
+ if ((ret > 0) || ((ret == 0) && (str1.Length() >= len)))
+ return true;
+ return false;
+}
+
+inline bool operator>= (const char *str1, const cTBString &str2) {
+ uint len = strlen(str1);
+ int ret = memcmp(str1, str2.Buffer(), len < str2.Length() ? len : str2.Length());
+ if ((ret > 0) || ((ret == 0) && (len >= str2.Length())))
+ return true;
+ return false;
+}
+
+#endif // TOOLBOX_STRING_H
diff --git a/tools/tools.c b/tools/tools.c
new file mode 100644
index 0000000..fa813fa
--- /dev/null
+++ b/tools/tools.c
@@ -0,0 +1,12 @@
+#include "tools/tools.h"
+
+#include <sys/time.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+void *operator new(size_t nSize, void *p) throw () {
+ return p;
+}
+
diff --git a/tools/tools.h b/tools/tools.h
new file mode 100644
index 0000000..ab00c60
--- /dev/null
+++ b/tools/tools.h
@@ -0,0 +1,67 @@
+#ifndef TOOLBOX_TOOLS_H
+#define TOOLBOX_TOOLS_H
+
+//#include <stdio.h>
+//#include <iostream>
+#include <sys/types.h>
+
+//#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