diff --git a/ftphoney.sln b/ftphoney.sln
new file mode 100644
index 0000000..9d1dea0
--- /dev/null
+++ b/ftphoney.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftphoney", "ftphoney\ftphoney.vcxproj", "{C70E332A-1CEB-4ABD-B84D-70C7751C88EB}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C70E332A-1CEB-4ABD-B84D-70C7751C88EB}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C70E332A-1CEB-4ABD-B84D-70C7751C88EB}.Debug|Win32.Build.0 = Debug|Win32
+ {C70E332A-1CEB-4ABD-B84D-70C7751C88EB}.Release|Win32.ActiveCfg = Release|Win32
+ {C70E332A-1CEB-4ABD-B84D-70C7751C88EB}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/ftphoney/ftphoney.vcxproj b/ftphoney/ftphoney.vcxproj
new file mode 100644
index 0000000..7c34034
--- /dev/null
+++ b/ftphoney/ftphoney.vcxproj
@@ -0,0 +1,86 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+
+ {C70E332A-1CEB-4ABD-B84D-70C7751C88EB}
+ Win32Proj
+ ftphoney
+
+
+
+ Application
+ true
+ Unicode
+
+
+ Application
+ false
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ $(SolutionDir)\include
+
+
+ Console
+ true
+ ws2_32.lib;ptypes_d.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ $(SolutionDir)\include
+
+
+ Console
+ true
+ true
+ true
+ ws2_32.lib;ptypes_r.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/include/ptypes/pasync.h b/include/ptypes/pasync.h
new file mode 100644
index 0000000..6eef4d6
--- /dev/null
+++ b/include/ptypes/pasync.h
@@ -0,0 +1,536 @@
+/*
+ *
+ * C++ Portable Types Library (PTypes)
+ * Version 2.1.1 Released 27-Jun-2007
+ *
+ * Copyright (C) 2001-2007 Hovik Melikyan
+ *
+ * http://www.melikyan.com/ptypes/
+ *
+ */
+
+#ifndef __PASYNC_H__
+#define __PASYNC_H__
+
+#ifdef WIN32
+# define _WINSOCKAPI_ // prevent inclusion of winsock.h, since we need winsock2.h
+# include
+#else
+# include
+# ifndef __bsdi__
+# include
+# endif
+#endif
+
+#ifndef __PPORT_H__
+#include "pport.h"
+#endif
+
+#ifndef __PTYPES_H__
+#include "ptypes.h"
+#endif
+
+
+PTYPES_BEGIN
+
+//
+// Summary of implementation:
+//
+// atomic increment/decrement/exchange
+// MSVC/BCC/i386: internal, asm
+// GCC/i386: internal, asm
+// GCC/PowerPC: internal, asm
+// GCC/SPARC: internal, asm
+// Other: internal, mutex hash table
+//
+// mutex
+// Win32: Critical section
+// Other: POSIX mutex
+//
+// trigger
+// Win32: Event
+// Other: internal, POSIX condvar/mutex
+//
+// rwlock:
+// Win32: internal, Event/mutex
+// MacOS: internal, POSIX condvar/mutex
+// Other: POSIX rwlock
+//
+// semaphore:
+// Win32: = timedsem
+// MacOS: = timedsem
+// Other: POSIX semaphore
+//
+// timedsem (with timed waiting):
+// Win32: Semaphore
+// Other: internal, POSIX mutex/condvar
+//
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 4)
+#endif
+
+
+#ifdef WIN32
+ typedef int pthread_id_t;
+ typedef HANDLE pthread_t;
+#else
+ typedef pthread_t pthread_id_t;
+#endif
+
+
+ptpublic void ptdecl psleep(uint milliseconds);
+ptpublic bool ptdecl pthrequal(pthread_id_t id); // note: this is NOT the thread handle, use thread::get_id()
+ptpublic pthread_id_t ptdecl pthrself(); // ... same
+
+
+// -------------------------------------------------------------------- //
+// --- mutex ---------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+#ifdef WIN32
+
+struct ptpublic mutex: public noncopyable
+{
+protected:
+ CRITICAL_SECTION critsec;
+public:
+ mutex() { InitializeCriticalSection(&critsec); }
+ ~mutex() { DeleteCriticalSection(&critsec); }
+ void enter() { EnterCriticalSection(&critsec); }
+ void leave() { LeaveCriticalSection(&critsec); }
+ void lock() { enter(); }
+ void unlock() { leave(); }
+};
+
+
+#else
+
+
+struct ptpublic mutex: public noncopyable
+{
+protected:
+ pthread_mutex_t mtx;
+public:
+ mutex() { pthread_mutex_init(&mtx, 0); }
+ ~mutex() { pthread_mutex_destroy(&mtx); }
+ void enter() { pthread_mutex_lock(&mtx); }
+ void leave() { pthread_mutex_unlock(&mtx); }
+ void lock() { enter(); }
+ void unlock() { leave(); }
+};
+
+#endif
+
+
+//
+// scopelock
+//
+
+class scopelock: public noncopyable
+{
+protected:
+ mutex* mtx;
+public:
+ scopelock(mutex& imtx): mtx(&imtx) { mtx->lock(); }
+ ~scopelock() { mtx->unlock(); }
+};
+
+
+//
+// mutex table for hashed memory locking (undocumented)
+//
+
+#define _MUTEX_HASH_SIZE 29 // a prime number for hashing
+
+#ifdef WIN32
+# define pmemlock mutex
+# define pmementer(m) (m)->lock()
+# define pmemleave(m) (m)->unlock()
+#else
+# define _MTX_INIT PTHREAD_MUTEX_INITIALIZER
+# define pmemlock pthread_mutex_t
+# define pmementer pthread_mutex_lock
+# define pmemleave pthread_mutex_unlock
+#endif
+
+
+ptpublic extern pmemlock _mtxtable[_MUTEX_HASH_SIZE];
+
+#define pgetmemlock(addr) (_mtxtable + pintptr(addr) % _MUTEX_HASH_SIZE)
+
+
+// -------------------------------------------------------------------- //
+// --- trigger -------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+#ifdef WIN32
+
+class ptpublic trigger: public noncopyable
+{
+protected:
+ HANDLE handle; // Event object
+public:
+ trigger(bool autoreset, bool state);
+ ~trigger() { CloseHandle(handle); }
+ void wait() { WaitForSingleObject(handle, INFINITE); }
+ void post() { SetEvent(handle); }
+ void signal() { post(); }
+ void reset() { ResetEvent(handle); }
+};
+
+
+#else
+
+
+class ptpublic trigger: public noncopyable
+{
+protected:
+ pthread_mutex_t mtx;
+ pthread_cond_t cond;
+ int state;
+ bool autoreset;
+public:
+ trigger(bool autoreset, bool state);
+ ~trigger();
+ void wait();
+ void post();
+ void signal() { post(); }
+ void reset();
+};
+
+#endif
+
+
+// -------------------------------------------------------------------- //
+// --- rwlock --------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+#if defined(WIN32) || defined(__DARWIN__) || defined(__bsdi__)
+# define __PTYPES_RWLOCK__
+#elif defined(linux)
+ // on Linux rwlocks are included only with -D_GNU_SOURCE.
+ // programs that don't use rwlocks, do not need to define
+ // _GNU_SOURCE either.
+# if defined(_GNU_SOURCE) || defined(__USE_UNIX98)
+# define __POSIX_RWLOCK__
+# endif
+#else
+# define __POSIX_RWLOCK__
+#endif
+
+
+#ifdef __PTYPES_RWLOCK__
+
+struct ptpublic rwlock: protected mutex
+{
+protected:
+#ifdef WIN32
+ HANDLE reading; // Event object
+ HANDLE finished; // Event object
+ int readcnt;
+ int writecnt;
+#else
+ pthread_mutex_t mtx;
+ pthread_cond_t readcond;
+ pthread_cond_t writecond;
+ int locks;
+ int writers;
+ int readers;
+#endif
+public:
+ rwlock();
+ ~rwlock();
+ void rdlock();
+ void wrlock();
+ void unlock();
+ void lock() { wrlock(); }
+};
+
+
+#elif defined(__POSIX_RWLOCK__)
+
+
+struct ptpublic rwlock: public noncopyable
+{
+protected:
+ pthread_rwlock_t rw;
+public:
+ rwlock();
+ ~rwlock() { pthread_rwlock_destroy(&rw); }
+ void rdlock() { pthread_rwlock_rdlock(&rw); }
+ void wrlock() { pthread_rwlock_wrlock(&rw); }
+ void unlock() { pthread_rwlock_unlock(&rw); }
+ void lock() { wrlock(); }
+};
+
+#endif
+
+
+#if defined(__PTYPES_RWLOCK__) || defined(__POSIX_RWLOCK__)
+
+//
+// scoperead & scopewrite
+//
+
+class scoperead: public noncopyable
+{
+protected:
+ rwlock* rw;
+public:
+ scoperead(rwlock& irw): rw(&irw) { rw->rdlock(); }
+ ~scoperead() { rw->unlock(); }
+};
+
+
+class scopewrite: public noncopyable
+{
+protected:
+ rwlock* rw;
+public:
+ scopewrite(rwlock& irw): rw(&irw) { rw->wrlock(); }
+ ~scopewrite() { rw->unlock(); }
+};
+
+
+#endif
+
+
+// -------------------------------------------------------------------- //
+// --- semaphore ------------------------------------------------------ //
+// -------------------------------------------------------------------- //
+
+
+#if defined(WIN32) || defined(__DARWIN__) || defined(__bsdi__)
+# define __SEM_TO_TIMEDSEM__
+#endif
+
+
+#ifdef __SEM_TO_TIMEDSEM__
+
+// map ordinary semaphore to timed semaphore
+
+class timedsem;
+typedef timedsem semaphore;
+
+
+#else
+
+
+class ptpublic semaphore: public unknown
+{
+protected:
+ sem_t handle;
+public:
+ semaphore(int initvalue);
+ virtual ~semaphore();
+
+ void wait();
+ void post();
+ void signal() { post(); }
+};
+
+#endif
+
+
+class ptpublic timedsem: public unknown
+{
+protected:
+#ifdef WIN32
+ HANDLE handle;
+#else
+ int count;
+ pthread_mutex_t mtx;
+ pthread_cond_t cond;
+#endif
+public:
+ timedsem(int initvalue);
+ virtual ~timedsem();
+ bool wait(int msecs = -1);
+ void post();
+ void signal() { post(); }
+};
+
+
+// -------------------------------------------------------------------- //
+// --- thread --------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+class ptpublic thread: public unknown
+{
+protected:
+#ifdef WIN32
+ unsigned id;
+#endif
+ pthread_t handle;
+ int autofree;
+ int running;
+ int signaled;
+ int finished;
+ int freed;
+ int reserved; // for priorities
+ timedsem relaxsem;
+
+ virtual void execute() = 0;
+ virtual void cleanup();
+
+ bool relax(int msecs) { return relaxsem.wait(msecs); }
+
+ friend void _threadepilog(thread* thr);
+
+#ifdef WIN32
+ friend unsigned __stdcall _threadproc(void* arg);
+#else
+ friend void* _threadproc(void* arg);
+#endif
+
+public:
+ thread(bool iautofree);
+ virtual ~thread();
+
+#ifdef WIN32
+ pthread_id_t get_id() { return int(id); }
+#else
+ pthread_id_t get_id() { return handle; }
+#endif
+
+ bool get_running() { return running != 0; }
+ bool get_finished() { return finished != 0; }
+ bool get_signaled() { return signaled != 0; }
+
+ void start();
+ void signal();
+ void waitfor();
+};
+
+
+
+// -------------------------------------------------------------------- //
+// --- jobqueue & msgqueue -------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+const int MSG_USER = 0;
+const int MSG_QUIT = -1;
+
+const int DEF_QUEUE_LIMIT = 5000;
+
+class ptpublic message: public unknown
+{
+protected:
+ message* next; // next in the message chain, used internally
+ semaphore* sync; // used internally by msgqueue::send(), when called from a different thread
+ friend class jobqueue; // my friends, job queue and message queue...
+ friend class msgqueue;
+public:
+ int id;
+ pintptr param;
+ pintptr result;
+ message(int iid, pintptr iparam = 0);
+ virtual ~message();
+};
+
+
+class ptpublic jobqueue: public noncopyable
+{
+private:
+ int limit; // queue limit
+ message* head; // queue head
+ message* tail; // queue tail
+ int qcount; // number of items in the queue
+ timedsem sem; // queue semaphore
+ timedsem ovrsem; // overflow semaphore
+ mutex qlock; // critical sections in enqueue and dequeue
+
+protected:
+ bool enqueue(message* msg, int timeout = -1);
+ bool push(message* msg, int timeout = -1);
+ message* dequeue(bool safe = true, int timeout = -1);
+ void purgequeue();
+
+public:
+ jobqueue(int ilimit = DEF_QUEUE_LIMIT);
+ virtual ~jobqueue();
+
+ int get_count() const { return qcount; }
+ int get_limit() const { return limit; }
+
+ bool post(message* msg, int timeout = -1);
+ bool post(int id, pintptr param = 0, int timeout = -1);
+ bool posturgent(message* msg, int timeout = -1);
+ bool posturgent(int id, pintptr param = 0, int timeout = -1);
+ message* getmessage(int timeout = -1);
+
+#ifdef PTYPES19_COMPAT
+ int msgsavail() const { return get_count(); }
+#endif
+};
+
+
+template class tjobqueue: protected jobqueue
+{
+public:
+ tjobqueue(int ilimit = DEF_QUEUE_LIMIT);
+
+ int get_count() const { return jobqueue::get_count(); }
+ int get_limit() const { return jobqueue::get_limit(); }
+ bool post(T* msg, int timeout = -1) { return jobqueue::post(msg, timeout); }
+ bool posturgent(T* msg, int timeout = -1) { return jobqueue::posturgent(msg, timeout); }
+ T* getmessage(int timeout = -1) { return (T*)jobqueue::getmessage(timeout); }
+};
+
+
+class ptpublic msgqueue: protected jobqueue
+{
+private:
+ mutex thrlock; // lock for the queue processing
+ pthread_id_t owner; // thread ID of the queue processing thread
+
+ pintptr finishmsg(message* msg);
+ void handlemsg(message* msg);
+ void takeownership();
+
+protected:
+ bool quit;
+
+ void defhandler(message& msg);
+ virtual void msghandler(message& msg) = 0;
+
+public:
+ msgqueue(int ilimit = DEF_QUEUE_LIMIT);
+ virtual ~msgqueue();
+
+ // functions calling from the owner thread:
+ void processone(); // process one message, may hang if no msgs in the queue
+ void processmsgs(); // process all available messages and return
+ void run(); // process messages until MSG_QUIT
+
+ // functions calling from any thread:
+ int get_count() const { return jobqueue::get_count(); }
+ int get_limit() const { return jobqueue::get_limit(); }
+ bool post(message* msg, int timeout = -1) { return jobqueue::post(msg, timeout); }
+ bool post(int id, pintptr param = 0, int timeout = -1) { return jobqueue::post(id, param, timeout); }
+ bool posturgent(message* msg, int timeout = -1) { return jobqueue::posturgent(msg, timeout); }
+ bool posturgent(int id, pintptr param = 0, int timeout = -1) { return jobqueue::posturgent(id, param, timeout); }
+ pintptr send(message* msg);
+ pintptr send(int id, pintptr param = 0);
+
+#ifdef PTYPES19_COMPAT
+ int msgsavail() const { return get_count(); }
+#endif
+};
+
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif
+
+
+PTYPES_END
+
+#endif // __PASYNC_H__
diff --git a/include/ptypes/pinet.h b/include/ptypes/pinet.h
new file mode 100644
index 0000000..8b3ceeb
--- /dev/null
+++ b/include/ptypes/pinet.h
@@ -0,0 +1,400 @@
+/*
+ *
+ * C++ Portable Types Library (PTypes)
+ * Version 2.1.1 Released 27-Jun-2007
+ *
+ * Copyright (C) 2001-2007 Hovik Melikyan
+ *
+ * http://www.melikyan.com/ptypes/
+ *
+ */
+
+#ifndef __PINET_H__
+#define __PINET_H__
+
+#ifndef __PPORT_H__
+#include "pport.h"
+#endif
+
+#ifndef __PTYPES_H__
+#include "ptypes.h"
+#endif
+
+#ifndef __PSTREAMS_H__
+#include "pstreams.h"
+#endif
+
+
+#ifdef WIN32
+# include
+#else
+# include // for socklen_t
+# include
+# include
+#endif
+
+
+PTYPES_BEGIN
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 4)
+#endif
+
+
+//
+// BSD-compatible socket error codes for Win32
+//
+
+#if defined(WSAENOTSOCK) && !defined(ENOTSOCK)
+
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EINPROGRESS WSAEINPROGRESS
+#define EALREADY WSAEALREADY
+#define ENOTSOCK WSAENOTSOCK
+#define EDESTADDRREQ WSAEDESTADDRREQ
+#define EMSGSIZE WSAEMSGSIZE
+#define EPROTOTYPE WSAEPROTOTYPE
+#define ENOPROTOOPT WSAENOPROTOOPT
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
+#define EOPNOTSUPP WSAEOPNOTSUPP
+#define EPFNOSUPPORT WSAEPFNOSUPPORT
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define EADDRINUSE WSAEADDRINUSE
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#define ENETDOWN WSAENETDOWN
+#define ENETUNREACH WSAENETUNREACH
+#define ENETRESET WSAENETRESET
+#define ECONNABORTED WSAECONNABORTED
+#define ECONNRESET WSAECONNRESET
+#define ENOBUFS WSAENOBUFS
+#define EISCONN WSAEISCONN
+#define ENOTCONN WSAENOTCONN
+#define ESHUTDOWN WSAESHUTDOWN
+#define ETOOMANYREFS WSAETOOMANYREFS
+#define ETIMEDOUT WSAETIMEDOUT
+#define ECONNREFUSED WSAECONNREFUSED
+#define ELOOP WSAELOOP
+// #define ENAMETOOLONG WSAENAMETOOLONG
+#define EHOSTDOWN WSAEHOSTDOWN
+#define EHOSTUNREACH WSAEHOSTUNREACH
+// #define ENOTEMPTY WSAENOTEMPTY
+#define EPROCLIM WSAEPROCLIM
+#define EUSERS WSAEUSERS
+#define EDQUOT WSAEDQUOT
+#define ESTALE WSAESTALE
+#define EREMOTE WSAEREMOTE
+
+// NOTE: these are not errno constants in UNIX!
+#define HOST_NOT_FOUND WSAHOST_NOT_FOUND
+#define TRY_AGAIN WSATRY_AGAIN
+#define NO_RECOVERY WSANO_RECOVERY
+#define NO_DATA WSANO_DATA
+
+#endif
+
+
+// shutdown() constants
+
+#if defined(SD_RECEIVE) && !defined(SHUT_RD)
+# define SHUT_RD SD_RECEIVE
+# define SHUT_WR SD_SEND
+# define SHUT_RDWR SD_BOTH
+#endif
+
+
+// max backlog value for listen()
+
+#ifndef SOMAXCONN
+# define SOMAXCONN -1
+#endif
+
+typedef char* sockval_t;
+
+#ifndef WIN32
+# define closesocket close
+#endif
+
+
+#if (defined(__DARWIN__) && !defined(_SOCKLEN_T)) || defined(WIN32) || defined(__hpux)
+ typedef int psocklen;
+#else
+ typedef socklen_t psocklen;
+#endif
+
+
+// -------------------------------------------------------------------- //
+// --- IP address class and DNS utilities ---------------------------- //
+// -------------------------------------------------------------------- //
+
+//
+// IP address
+//
+
+struct ptpublic ipaddress
+{
+public:
+ union
+ {
+ uchar data[4];
+ ulong ldata;
+ };
+ ipaddress() {}
+ ipaddress(ulong a) { ldata = a; }
+ ipaddress(const ipaddress& a) { ldata = a.ldata; }
+ ipaddress(int a, int b, int c, int d);
+ ipaddress& operator= (ulong a) { ldata = a; return *this; }
+ ipaddress& operator= (const ipaddress& a) { ldata = a.ldata; return *this; }
+ uchar& operator [] (int i) { return data[i]; }
+ operator ulong() const { return ldata; }
+};
+
+
+ptpublic extern ipaddress ipnone;
+ptpublic extern ipaddress ipany;
+ptpublic extern ipaddress ipbcast;
+
+
+//
+// IP peer info: host name, IP and the port name
+// used internally in ipstream and ipmessage
+//
+
+
+class ptpublic ippeerinfo: public noncopyable
+{
+protected:
+ ipaddress ip; // target IP
+ string host; // target host name; either IP or hostname must be specified
+ int port; // target port number
+
+ void notfound(); // throws a (estream*) exception
+
+ ptpublic friend bool ptdecl psockname(int, ippeerinfo&);
+
+public:
+ ippeerinfo();
+ ippeerinfo(ipaddress iip, const string& ihost, int iport);
+
+ ipaddress get_ip(); // resolves the host name if necessary (only once)
+ string get_host(); // performs reverse-lookup if necessary (only once)
+ int get_port() { return port; }
+ void clear();
+ string asstring(bool showport) const;
+};
+
+
+ptpublic string ptdecl iptostring(ipaddress ip);
+ptpublic ipaddress ptdecl phostbyname(const char* name);
+ptpublic string ptdecl phostbyaddr(ipaddress ip);
+ptpublic string ptdecl phostcname(const char* name);
+
+// internal utilities
+ptpublic int ptdecl usockerrno();
+ptpublic const char* ptdecl usockerrmsg(int code);
+ptpublic bool ptdecl psockwait(int handle, int timeout);
+ptpublic bool ptdecl psockname(int handle, ippeerinfo&);
+
+
+// -------------------------------------------------------------------- //
+// --- TCP socket classes -------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+// additional IO status codes
+
+const int IO_RESOLVING = 10;
+const int IO_RESOLVED = 11;
+const int IO_CONNECTING = 20;
+const int IO_CONNECTED = 21;
+
+
+//
+// ipstream
+//
+
+class ptpublic ipstream: public fdxstm, public ippeerinfo
+{
+ friend class ipstmserver;
+
+protected:
+ int svsocket; // server socket descriptor, used internally by ipstmserver
+
+#ifdef WIN32
+ // sockets are not compatible with file handles on Windows
+ virtual int dorawread(char* buf, int count);
+ virtual int dorawwrite(const char* buf, int count);
+#endif
+
+ virtual int uerrno();
+ virtual const char* uerrmsg(int code);
+ virtual void doopen();
+ virtual large doseek(large newpos, ioseekmode mode);
+ virtual void doclose();
+ virtual void sockopt(int socket);
+ void closehandle();
+
+public:
+ ipstream();
+ ipstream(ipaddress ip, int port);
+ ipstream(const char* host, int port);
+ ipstream(const string& host, int port);
+ virtual ~ipstream();
+ virtual int classid();
+
+ virtual string get_streamname();
+
+ bool waitfor(int timeout);
+ ipaddress get_myip();
+ int get_myport();
+ void set_ip(ipaddress);
+ void set_host(const string&);
+ void set_host(const char*);
+ void set_port(int);
+};
+
+
+//
+// common internal interfaces for ipstmserver and ipmsgserver
+//
+
+class ipbindinfo: public unknown, public ippeerinfo
+{
+public:
+ int handle;
+
+ ipbindinfo(ipaddress iip, const string& ihost, int iport);
+ virtual ~ipbindinfo();
+};
+
+
+class ptpublic ipsvbase: public unknown
+{
+protected:
+ int socktype;
+ bool active;
+ tobjlist addrlist; // list of local socket addresses to bind to
+
+ void error(ippeerinfo& peer, int code, const char* defmsg);
+ bool dopoll(int* i, int timeout);
+ void setupfds(void* set, int i);
+ virtual void open();
+ virtual void close();
+ virtual void dobind(ipbindinfo*) = 0;
+ virtual void sockopt(int socket);
+
+public:
+ ipsvbase(int isocktype);
+ virtual ~ipsvbase();
+
+ int bind(ipaddress ip, int port);
+ int bindall(int port);
+
+ int get_addrcount() { return addrlist.get_count(); }
+ const ipbindinfo& get_addr(int i) { return *addrlist[i]; }
+ void clear();
+};
+
+
+//
+// ipstmserver
+//
+
+class ptpublic ipstmserver: public ipsvbase
+{
+protected:
+ virtual void dobind(ipbindinfo*);
+
+public:
+ ipstmserver();
+ virtual ~ipstmserver();
+
+ bool poll(int i = -1, int timeout = 0);
+ bool serve(ipstream& client, int i = -1, int timeout = -1);
+};
+
+
+// -------------------------------------------------------------------- //
+// --- UDP socket classes -------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+//
+// ipmessage
+//
+
+class ptpublic ipmessage: public unknown, public ippeerinfo
+{
+protected:
+ int handle;
+
+ void error(int code, const char* msg);
+ void open();
+ void close();
+ virtual void sockopt(int socket);
+
+public:
+ ipmessage();
+ ipmessage(ipaddress ip, int port);
+ ipmessage(const char* host, int port);
+ ipmessage(const string& host, int port);
+ virtual ~ipmessage();
+
+ void set_ip(ipaddress iip);
+ void set_host(const string&);
+ void set_host(const char*);
+ void set_port(int);
+ ipaddress get_myip();
+ int get_myport();
+ int get_handle() { return handle; }
+
+ bool waitfor(int timeout);
+ int receive(char* buf, int count, ipaddress& src);
+ int receive(char* buf, int count);
+ string receive(int max, ipaddress& src);
+ string receive(int max);
+ void send(const char* buf, int count);
+ void send(const string& s) { send(s, length(s)); }
+};
+
+
+//
+// ipmsgserver
+//
+
+class ptpublic ipmsgserver: public ipsvbase, public ippeerinfo
+{
+protected:
+ int handle;
+
+ virtual void close();
+ virtual void dobind(ipbindinfo*);
+
+public:
+ ipmsgserver();
+ virtual ~ipmsgserver();
+
+ int get_handle() { return handle; }
+
+ bool poll(int i = -1, int timeout = 0);
+ int receive(char* buf, int count);
+ string receive(int max);
+ void send(const char* buf, int count);
+ void send(const string& s) { send(s, length(s)); }
+ void sendto(const char* buf, int count, ipaddress ip, int port);
+ void sendto(const string& s, ipaddress ip, int port)
+ { sendto(s, length(s), ip, port); }
+};
+
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif
+
+
+PTYPES_END
+
+
+#endif // __PINET_H__
+
diff --git a/include/ptypes/pport.h b/include/ptypes/pport.h
new file mode 100644
index 0000000..9fcfcec
--- /dev/null
+++ b/include/ptypes/pport.h
@@ -0,0 +1,206 @@
+/*
+ *
+ * C++ Portable Types Library (PTypes)
+ * Version 2.1.1 Released 27-Jun-2007
+ *
+ * Copyright (C) 2001-2007 Hovik Melikyan
+ *
+ * http://www.melikyan.com/ptypes/
+ *
+ */
+
+#ifndef __PPORT_H__
+#define __PPORT_H__
+
+
+#if defined(linux)
+# include // for uintptr_t
+#endif
+
+#include
+
+
+#ifndef __cplusplus
+# error "This is a C++ source"
+#endif
+
+
+#define PTYPES_NAMESPACE pt
+
+//
+// conditional namespace declarations
+//
+
+#ifdef PTYPES_NAMESPACE
+# define PTYPES_BEGIN namespace PTYPES_NAMESPACE {
+# define PTYPES_END }
+# define USING_PTYPES using namespace PTYPES_NAMESPACE;
+#else
+# define PTYPES_NAMESPACE
+# define PTYPES_BEGIN
+# define PTYPES_END
+# define USING_PTYPES
+#endif
+
+
+//
+// Windows DLL export/import and calling convention macros
+//
+
+#ifdef WIN32
+# if defined(PTYPES_DLL_EXPORTS)
+# define ptpublic __declspec(dllexport)
+# elif defined(PTYPES_DLL)
+# define ptpublic __declspec(dllimport)
+# else
+# define ptpublic
+# endif
+# define ptdecl __stdcall
+# define __PFASTCALL __fastcall
+#else
+# define ptpublic
+# define ptdecl
+# define __PFASTCALL
+#endif
+
+
+//
+// versioning
+//
+
+
+extern "C" ptpublic unsigned long __ptypes_version;
+
+// this enables old algebraic list interfaces; NO_PTYPES19_COMPAT
+// can be defined at command line
+#if !defined(NO_PTYPES19_COMPAT)
+# define PTYPES19_COMPAT
+#endif
+
+
+PTYPES_BEGIN
+
+
+#ifdef _MSC_VER
+// we don't want "unreferenced inline function" warning
+# pragma warning (disable: 4514)
+// ... also "copy constructor/assignment operator could not be generated"
+# pragma warning (disable: 4511)
+# pragma warning (disable: 4512)
+// disable deprecation warnings for snprintf and others
+# pragma warning (disable: 4996)
+#endif
+
+#if defined(_DEBUG) && !defined(DEBUG)
+# define DEBUG
+#endif
+
+#if defined(__WIN32__) && !defined(WIN32)
+# define WIN32
+#endif
+
+// __APPLE__ is the only predefined macro on MacOS X
+#if defined(__APPLE__)
+# define __DARWIN__
+#endif
+
+// CHECK_BOUNDS enables bounds checking for strings and lists
+#if defined(DEBUG) && !defined(CHECK_BOUNDS)
+# define CHECK_BOUNDS
+#endif
+
+// COUNT_OBJALLOC helps to keep track of the number of
+// objects created/destroyed
+#if defined(DEBUG) && !defined(COUNT_OBJALLOC)
+# define COUNT_OBJALLOC
+#endif
+
+
+//
+// useful typedefs
+//
+
+typedef unsigned int uint;
+typedef unsigned long ulong;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+typedef char* pchar;
+typedef const char* pconst;
+typedef void* ptr;
+typedef int* pint;
+
+#ifdef WIN32
+ typedef uint pintptr;
+#else
+ typedef uintptr_t pintptr;
+#endif
+
+
+//
+// portable 64-bit integers
+//
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+ typedef __int64 large;
+ typedef unsigned __int64 ularge;
+# define LLCONST(a) (a##i64)
+#else
+ typedef long long large;
+ typedef unsigned long long ularge;
+# define LLCONST(a) (a##ll)
+#endif
+
+#define LARGE_MIN (LLCONST(-9223372036854775807)-1)
+#define LARGE_MAX (LLCONST(9223372036854775807))
+#define ULARGE_MAX (LLCONST(18446744073709551615u))
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+# define strcasecmp stricmp
+# define snprintf _snprintf
+#endif
+
+
+//
+// misc.
+//
+
+// I like Pascal's nil
+#define nil 0
+
+inline int imax(int x, int y) { return (x > y) ? x : y; }
+inline int imin(int x, int y) { return (x < y) ? x : y; }
+inline large lmax(large x, large y) { return (x > y) ? x : y; }
+inline large lmin(large x, large y) { return (x < y) ? x : y; }
+
+
+//
+// critical error processing
+//
+
+#define CRIT_FIRST 0xC0000
+
+typedef void (ptdecl *_pcrithandler)(int code, const char* msg);
+
+ptpublic _pcrithandler ptdecl getcrithandler();
+ptpublic _pcrithandler ptdecl setcrithandler(_pcrithandler newh);
+
+ptpublic void ptdecl fatal(int code, const char* msg);
+
+
+//
+// memory management (undocumented)
+// hides some BSD* incompatibility issues
+//
+
+ptpublic void* ptdecl memalloc(uint a);
+ptpublic void* ptdecl memrealloc(void* p, uint a);
+ptpublic void ptdecl memfree(void* p);
+ptpublic void ptdecl memerror();
+ptpublic int ptdecl memquantize(int);
+
+
+PTYPES_END
+
+
+#endif // __PPORT_H__
diff --git a/include/ptypes/pstreams.h b/include/ptypes/pstreams.h
new file mode 100644
index 0000000..3495725
--- /dev/null
+++ b/include/ptypes/pstreams.h
@@ -0,0 +1,807 @@
+/*
+ *
+ * C++ Portable Types Library (PTypes)
+ * Version 2.1.1 Released 27-Jun-2007
+ *
+ * Copyright (C) 2001-2007 Hovik Melikyan
+ *
+ * http://www.melikyan.com/ptypes/
+ *
+ */
+
+#ifndef __PSTREAMS_H__
+#define __PSTREAMS_H__
+
+#ifndef __PPORT_H__
+#include "pport.h"
+#endif
+
+#ifndef __PTYPES_H__
+#include "ptypes.h"
+#endif
+
+#ifndef PTYPES_ST
+# ifndef __PASYNC_H__
+# include "pasync.h" // for logfile.lock
+# endif
+#endif
+
+#include
+#include
+
+
+#ifdef WIN32
+# define _WINSOCKAPI_ // prevent inclusion of winsock.h, because we need winsock2.h
+# include "windows.h" // for OVERLAPPED
+#endif
+
+
+PTYPES_BEGIN
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 4)
+#endif
+
+
+// -------------------------------------------------------------------- //
+// --- abstract stream i/o classes ----------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+//
+// stream exception class
+//
+
+class iobase;
+
+class ptpublic estream: public exception
+{
+protected:
+ int code;
+ iobase* errstm;
+public:
+ estream(iobase* ierrstm, int icode, const char* imsg);
+ estream(iobase* ierrstm, int icode, const string& imsg);
+ virtual ~estream();
+ int get_code() { return code; }
+ iobase* get_errstm() { return errstm; }
+};
+
+
+typedef void (ptdecl *iostatusevent)(iobase* sender, int code);
+
+ptpublic int ptdecl unixerrno();
+ptpublic const char* ptdecl unixerrmsg(int code);
+
+
+// status codes: compatible with WinInet API
+// additional status codes are defined in pinet.h for ipsocket
+
+const int IO_CREATED = 1;
+const int IO_OPENING = 5;
+const int IO_OPENED = 35;
+const int IO_READING = 37;
+const int IO_WRITING = 38;
+const int IO_EOF = 45;
+const int IO_CLOSING = 250;
+const int IO_CLOSED = 253;
+
+
+//
+// iobase
+//
+
+enum ioseekmode
+{
+ IO_BEGIN,
+ IO_CURRENT,
+ IO_END
+};
+
+
+const int invhandle = -1;
+
+
+class ptpublic iobase: public component
+{
+ friend class fdxoutstm;
+
+protected:
+ bool active; // active status, changed by open() and close()
+ bool cancelled; // the stream was cancelled by cancel()
+ bool eof; // end of file reached, only for input streams
+ int handle; // used in many derivative classes
+ large abspos; // physical stream position
+ int bufsize; // buffer size, can be changed only when not active
+ char* bufdata; // internal: allocated buffer data
+ int bufpos; // internal: current position
+ int bufend; // internal: current data size in the buffer
+ int stmerrno; // UNIX-compatible error numbers, see comments in piobase.cxx
+ string deferrormsg; // internal: default error message when an exception is thrown,
+ int status; // stream status code, see IO_xxx constants above
+ iostatusevent onstatus; // user-defined status change handler
+
+ virtual void bufalloc();
+ virtual void buffree();
+ void bufclear() { bufpos = 0; bufend = 0; }
+
+ void errstminactive();
+ void errbufrequired();
+ void requireactive() { if (!active) errstminactive(); }
+ void requirebuf() { requireactive(); if (bufdata == 0) errbufrequired(); }
+ int convertoffset(large);
+
+ virtual void doopen() = 0;
+ virtual void doclose();
+ virtual large doseek(large newpos, ioseekmode mode);
+
+ virtual void chstat(int newstat);
+ virtual int uerrno();
+ virtual const char* uerrmsg(int code);
+
+public:
+ iobase(int ibufsize = -1);
+ virtual ~iobase();
+
+ void open();
+ void close();
+ void cancel();
+ void reopen() { open(); }
+ large seekx(large newpos, ioseekmode mode = IO_BEGIN);
+ int seek(int newpos, ioseekmode mode = IO_BEGIN) { return convertoffset(seekx(newpos, mode)); }
+ void error(int code, const char* defmsg);
+ virtual void flush();
+
+ virtual string get_errormsg();
+ virtual string get_errstmname();
+ virtual string get_streamname() = 0;
+
+ bool get_active() { return active; }
+ void set_active(bool newval);
+ bool get_cancelled() { return cancelled; }
+ void set_cancelled(bool newval) { cancelled = newval; }
+ int get_handle() { return handle; }
+ int get_bufsize() { return bufsize; }
+ void set_bufsize(int newval);
+ int get_stmerrno() { return stmerrno; }
+ int get_status() { return status; }
+ iostatusevent get_onstatus() { return onstatus; }
+ void set_onstatus(iostatusevent newval) { onstatus = newval; }
+};
+typedef iobase* piobase;
+
+
+ptpublic extern int defbufsize;
+ptpublic extern int stmbalance;
+
+
+//
+// instm - abstract input stream
+//
+
+const char eofchar = 0;
+
+class ptpublic instm: public iobase
+{
+protected:
+ virtual int dorawread(char* buf, int count);
+ int rawread(char* buf, int count);
+ virtual void bufvalidate();
+ void skipeol();
+
+public:
+ instm(int ibufsize = -1);
+ virtual ~instm();
+ virtual int classid();
+
+ bool get_eof();
+ void set_eof(bool ieof) { eof = ieof; }
+ bool get_eol();
+ int get_dataavail();
+ char preview();
+ char get();
+ void putback();
+ string token(const cset& chars);
+ string token(const cset& chars, int limit);
+ int token(const cset& chars, char* buf, int size);
+ string line();
+ string line(int limit);
+ int line(char* buf, int size, bool eateol = true);
+ int read(void* buf, int count);
+ int skip(int count);
+ int skiptoken(const cset& chars);
+ void skipline(bool eateol = true);
+ large tellx();
+ int tell() { return convertoffset(tellx()); }
+ large seekx(large newpos, ioseekmode mode = IO_BEGIN);
+ int seek(int newpos, ioseekmode mode = IO_BEGIN) { return convertoffset(seekx(newpos, mode)); }
+};
+typedef instm* pinstm;
+
+
+//
+// outstm - abstract output stream
+//
+
+class ptpublic outstm: public iobase
+{
+protected:
+ bool flusheol;
+
+ virtual int dorawwrite(const char* buf, int count);
+ int rawwrite(const char* buf, int count);
+ virtual void bufvalidate();
+ void bufadvance(int delta)
+ { bufpos += delta; if (bufend < bufpos) bufend = bufpos; }
+ bool canwrite();
+
+public:
+ outstm(bool iflusheol = false, int ibufsize = -1);
+ virtual ~outstm();
+ virtual int classid();
+
+ bool get_flusheol() { return flusheol; }
+ void set_flusheol(bool newval) { flusheol = newval; }
+
+ virtual void flush();
+ bool get_eof() { return eof; }
+ void put(char c);
+ void put(const char* str);
+ void put(const string& str);
+ void vputf(const char* fmt, va_list);
+ void putf(const char* fmt, ...);
+ void putline(const char* str);
+ void putline(const string& str);
+ void puteol();
+ int write(const void* buf, int count);
+ large tellx() { return abspos + bufpos; }
+ int tell() { return convertoffset(tellx()); }
+ large seekx(large newpos, ioseekmode mode = IO_BEGIN);
+ int seek(int newpos, ioseekmode mode = IO_BEGIN) { return convertoffset(seekx(newpos, mode)); }
+};
+typedef outstm* poutstm;
+
+
+// %t and %T formats
+ptpublic extern char* shorttimefmt; // "%d-%b-%Y %X"
+ptpublic extern char* longtimefmt; // "%a %b %d %X %Y"
+
+
+//
+// internal class used in fdxstm
+//
+
+class ptpublic fdxstm;
+
+
+class ptpublic fdxoutstm: public outstm
+{
+ friend class fdxstm;
+
+protected:
+ fdxstm* in;
+ virtual void chstat(int newstat);
+ virtual int uerrno();
+ virtual const char* uerrmsg(int code);
+ virtual void doopen();
+ virtual void doclose();
+ virtual int dorawwrite(const char* buf, int count);
+
+public:
+ fdxoutstm(int ibufsize, fdxstm* iin);
+ virtual ~fdxoutstm();
+ virtual string get_streamname();
+};
+typedef fdxstm* pfdxstm;
+
+
+//
+// fdxstm: abstract full-duplex stream (for sockets and pipes)
+//
+
+class ptpublic fdxstm: public instm
+{
+ friend class fdxoutstm;
+
+protected:
+ fdxoutstm out;
+
+ virtual int dorawwrite(const char* buf, int count);
+
+public:
+
+ fdxstm(int ibufsize = -1);
+ virtual ~fdxstm();
+ virtual int classid();
+
+ void set_bufsize(int newval); // sets both input and output buffer sizes
+
+ void open(); // rewritten to pass the call to the output stream too
+ void close();
+ void cancel();
+ virtual void flush();
+ large tellx(bool); // true for input and false for output
+ int tell(bool forin) { return convertoffset(tellx(forin)); }
+
+ // output interface: pretend this class is derived both
+ // from instm and outstm. actually we can't use multiple
+ // inheritance here, since this is a full-duplex stream,
+ // hence everything must be duplicated for input and output
+ void putf(const char* fmt, ...);
+ void put(char c) { out.put(c); }
+ void put(const char* str) { out.put(str); }
+ void put(const string& str) { out.put(str); }
+ void putline(const char* str) { out.putline(str); }
+ void putline(const string& str) { out.putline(str); }
+ void puteol() { out.puteol(); }
+ int write(const void* buf, int count) { return out.write(buf, count); }
+ bool get_flusheol() { return out.get_flusheol(); }
+ void set_flusheol(bool newval) { out.set_flusheol(newval); }
+
+ operator outstm&() { return out; }
+};
+
+
+//
+// abstract input filter class
+//
+
+class ptpublic infilter: public instm
+{
+protected:
+ instm* stm;
+ char* savebuf;
+ int savecount;
+ string postponed;
+
+ void copytobuf(string& s);
+ void copytobuf(pconst& buf, int& count);
+ bool copytobuf(char c);
+
+ virtual void freenotify(component* sender);
+ virtual void doopen();
+ virtual void doclose();
+ virtual int dorawread(char* buf, int count);
+ virtual void dofilter() = 0;
+
+ bool bufavail() { return savecount > 0; }
+ void post(const char* buf, int count);
+ void post(const char* s);
+ void post(char c);
+ virtual void post(string s);
+
+public:
+ infilter(instm* istm, int ibufsize = -1);
+ virtual ~infilter();
+
+ virtual string get_errstmname();
+
+ instm* get_stm() { return stm; }
+ void set_stm(instm* stm);
+};
+
+
+//
+// abstract output filter class
+//
+
+class ptpublic outfilter: public outstm
+{
+protected:
+ outstm* stm;
+ virtual void freenotify(component* sender);
+ virtual void doopen();
+ virtual void doclose();
+
+public:
+ outfilter(outstm* istm, int ibufsize = -1);
+ virtual ~outfilter();
+ virtual string get_errstmname();
+ outstm* get_stm() { return stm; }
+ void set_stm(outstm* stm);
+};
+
+
+//
+// inmemory - memory stream
+//
+
+class ptpublic inmemory: public instm
+{
+protected:
+ string mem;
+ virtual void bufalloc();
+ virtual void buffree();
+ virtual void bufvalidate();
+ virtual void doopen();
+ virtual void doclose();
+ virtual large doseek(large newpos, ioseekmode mode);
+ virtual int dorawread(char* buf, int count);
+
+public:
+ inmemory(const string& imem);
+ virtual ~inmemory();
+ virtual int classid();
+ virtual string get_streamname();
+ large seekx(large newpos, ioseekmode mode = IO_BEGIN);
+ int seek(int newpos, ioseekmode mode = IO_BEGIN) { return convertoffset(seekx(newpos, mode)); }
+ string get_strdata() { return mem; }
+ void set_strdata(const string& data);
+};
+
+
+//
+// outmemory - memory stream
+//
+
+class ptpublic outmemory: public outstm
+{
+protected:
+ string mem;
+ int limit;
+
+ virtual void doopen();
+ virtual void doclose();
+ virtual large doseek(large newpos, ioseekmode mode);
+ virtual int dorawwrite(const char* buf, int count);
+
+public:
+ outmemory(int limit = -1);
+ virtual ~outmemory();
+ virtual int classid();
+ virtual string get_streamname();
+ large tellx() { return abspos; }
+ int tell() { return (int)abspos; }
+ string get_strdata();
+};
+
+
+// -------------------------------------------------------------------- //
+// --- file input/output --------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+//
+// infile - file input
+//
+
+class outfile;
+
+class ptpublic infile: public instm
+{
+protected:
+ string filename;
+ int syshandle; // if not -1, assigned to handle in open() instead of opening a file by a name
+ int peerhandle; // pipe peer handle, needed for closing the peer after fork() on unix
+
+ virtual void doopen();
+ virtual void doclose();
+
+public:
+ infile();
+ infile(const char* ifn);
+ infile(const string& ifn);
+ virtual ~infile();
+ virtual int classid();
+
+ void pipe(outfile&);
+ virtual string get_streamname();
+ int get_syshandle() { return syshandle; }
+ void set_syshandle(int ihandle) { close(); syshandle = ihandle; }
+ int get_peerhandle() { return peerhandle; }
+ string get_filename() { return filename; }
+ void set_filename(const string& ifn) { close(); filename = ifn; }
+ void set_filename(const char* ifn) { close(); filename = ifn; }
+};
+
+
+//
+// outfile - file output
+//
+
+class ptpublic outfile: public outstm
+{
+protected:
+ friend class infile; // infile::pipe() needs access to peerhandle
+
+ string filename;
+ int syshandle; // if not -1, assigned to handle in open() instead of opening a file by a name
+ int peerhandle; // pipe peer handle, needed for closing the peer after fork() on unix
+ int umode; // unix file mode (unix only), default = 644
+ bool append; // append (create new if needed), default = false
+
+ virtual void doopen();
+ virtual void doclose();
+
+public:
+ outfile();
+ outfile(const char* ifn, bool iappend = false);
+ outfile(const string& ifn, bool iappend = false);
+ virtual ~outfile();
+ virtual int classid();
+
+ virtual void flush();
+ virtual string get_streamname();
+
+ int get_syshandle() { return syshandle; }
+ void set_syshandle(int ihandle) { close(); syshandle = ihandle; }
+ int get_peerhandle() { return peerhandle; }
+ string get_filename() { return filename; }
+ void set_filename(const string& ifn) { close(); filename = ifn; }
+ void set_filename(const char* ifn) { close(); filename = ifn; }
+ bool get_append() { return append; }
+ void set_append(bool iappend) { close(); append = iappend; }
+ int get_umode() { return umode; }
+ void set_umode(int iumode) { close(); umode = iumode; }
+};
+
+
+//
+// logfile - file output with thread-safe putf()
+//
+
+class ptpublic logfile: public outfile
+{
+protected:
+#ifndef PTYPES_ST
+ mutex lock;
+#endif
+public:
+ logfile();
+ logfile(const char* ifn, bool iappend = true);
+ logfile(const string& ifn, bool iappend = true);
+ virtual ~logfile();
+ virtual int classid();
+
+ void vputf(const char* fmt, va_list);
+ void putf(const char* fmt, ...);
+};
+
+
+//
+// intee - UNIX tee-style utility class
+//
+
+class ptpublic intee: public infilter {
+protected:
+ outfile file;
+ virtual void doopen();
+ virtual void doclose();
+ virtual void dofilter();
+public:
+ intee(instm* istm, const char* ifn, bool iappend = false);
+ intee(instm* istm, const string& ifn, bool iappend = false);
+ virtual ~intee();
+
+ outfile* get_file() { return &file; }
+ virtual string get_streamname();
+};
+
+
+// -------------------------------------------------------------------- //
+// --- named pipes --------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+// on Unix this directory can be overridden by providing the
+// full path, e.g. '/var/run/mypipe'. the path is ignored on
+// Windows and is always replaced with '\\\pipe\'
+
+#ifndef WIN32
+# define DEF_NAMED_PIPES_DIR "/tmp/"
+#endif
+
+
+#ifdef WIN32
+
+const int DEF_PIPE_TIMEOUT = 20000; // in milliseconds, for reading and writing
+const int DEF_PIPE_OPEN_TIMEOUT = 1000; // for connecting to the remote pipe:
+const int DEF_PIPE_OPEN_RETRY = 5; // will double the timeout value for each retry,
+ // i.e. 1 second, then 2, then 4 etc.
+const int DEF_PIPE_SYSTEM_BUF_SIZE = 4096;
+
+#endif
+
+
+class ptpublic namedpipe: public fdxstm
+{
+ friend class npserver;
+
+protected:
+ string pipename;
+ int svhandle;
+
+#ifdef WIN32
+ // we use overlapped IO in order to have timed waiting in serve()
+ // and also to implement timeout error on the client side
+ OVERLAPPED ovr;
+ virtual int dorawread(char* buf, int count);
+ virtual int dorawwrite(const char* buf, int count);
+ static string ptdecl realpipename(const string& pipename, const string& svrname = nullstring);
+ void initovr();
+#else
+ static string realpipename(const string& pipename);
+ static bool setupsockaddr(const string& pipename, void* sa);
+ void initovr() {}
+#endif
+
+ virtual void doopen();
+ virtual void doclose();
+ virtual large doseek(large, ioseekmode);
+
+public:
+ namedpipe();
+ namedpipe(const string& ipipename);
+#ifdef WIN32
+ namedpipe(const string& ipipename, const string& servername);
+#endif
+ virtual ~namedpipe();
+ virtual int classid();
+
+ virtual void flush();
+ virtual string get_streamname();
+
+ string get_pipename() { return pipename; }
+ void set_pipename(const string&);
+ void set_pipename(const char*);
+};
+
+
+class ptpublic npserver: public unknown
+{
+ string pipename;
+ int handle;
+ bool active;
+
+ void error(int code, const char* defmsg);
+ void open();
+ void close();
+#ifdef WIN32
+ void openinst();
+ void closeinst();
+#endif
+
+public:
+ npserver(const string& ipipename);
+ ~npserver();
+
+ bool serve(namedpipe& client, int timeout = -1);
+};
+
+
+// -------------------------------------------------------------------- //
+// --- utility streams ----------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+//
+// MD5 -- message digest algorithm
+// Derived from L. Peter Deutsch's work, please see src/pmd5.cxx
+//
+
+
+const int md5_digsize = 16;
+typedef uchar md5_digest[md5_digsize];
+
+// from md5.h
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+
+typedef struct md5_state_s
+{
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+
+class ptpublic outmd5: public outfilter
+{
+protected:
+ md5_state_s ctx;
+ md5_digest digest;
+
+ virtual void doopen();
+ virtual void doclose();
+ virtual int dorawwrite(const char* buf, int count);
+
+public:
+ outmd5(outstm* istm = nil);
+ virtual ~outmd5();
+
+ virtual string get_streamname();
+
+ const unsigned char* get_bindigest() { close(); return digest; }
+ string get_digest();
+};
+
+
+//
+// null output stream
+//
+
+
+class ptpublic outnull: public outstm
+{
+protected:
+ virtual int dorawwrite(const char*, int);
+ virtual void doopen();
+ virtual void doclose();
+public:
+ outnull();
+ virtual ~outnull();
+ virtual string get_streamname();
+};
+
+
+// -------------------------------------------------------------------- //
+// --- unit ---------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+#ifdef _MSC_VER
+// disable "type name first seen using 'struct' now seen using 'class'" warning
+# pragma warning (disable: 4099)
+// disable "class '...' needs to have dll-interface to be used by clients of class
+// '...'" warning, since the compiler may sometimes give this warning incorrectly.
+# pragma warning (disable: 4251)
+#endif
+
+class unit_thread;
+
+class ptpublic unit: public component
+{
+protected:
+ friend class unit_thread;
+
+ unit* pipe_next; // next unit in the pipe chain, assigned by connect()
+ unit_thread* main_thread; // async execution thread, started by run() if necessary
+ int running; // running status, to protect from recursive calls to run() and waitfor()
+
+ void do_main();
+
+public:
+ compref uin;
+ compref uout;
+
+ unit();
+ virtual ~unit();
+ virtual int classid();
+
+ // things that may be overridden in descendant classes
+ virtual void main(); // main code, called from run()
+ virtual void cleanup(); // main code cleanup, called from run()
+
+ // service methods
+ void connect(unit* next);
+ void run(bool async = false);
+ void waitfor();
+};
+typedef unit* punit;
+
+
+typedef unit CUnit; // send me a $10 check if you use this alias (not obligatory though,
+ // because the library is free, after all)
+
+
+//
+// standard input, output and error devices
+//
+
+ptpublic extern infile pin;
+ptpublic extern logfile pout;
+ptpublic extern logfile perr;
+ptpublic extern outnull pnull;
+
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif
+
+
+PTYPES_END
+
+#endif // __PSTREAMS_H__
+
diff --git a/include/ptypes/ptime.h b/include/ptypes/ptime.h
new file mode 100644
index 0000000..24d53ed
--- /dev/null
+++ b/include/ptypes/ptime.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * C++ Portable Types Library (PTypes)
+ * Version 2.1.1 Released 27-Jun-2007
+ *
+ * Copyright (C) 2001-2007 Hovik Melikyan
+ *
+ * http://www.melikyan.com/ptypes/
+ *
+ */
+
+#ifndef __PTIME_H__
+#define __PTIME_H__
+
+#ifndef __PPORT_H__
+#include "pport.h"
+#endif
+
+#ifndef __PTYPES_H__
+#include "ptypes.h"
+#endif
+
+
+#include
+
+
+PTYPES_BEGIN
+
+// datetime type: 64-bit, number of milliseconds since midnight 01/01/0001
+typedef large datetime;
+
+#define invdatetime LLCONST(-1)
+
+#define _msecsmax 86400000 // number of milliseconds in one day
+#define _daysmax 3652059 // number of days between 01/01/0001 and 12/31/9999
+#define _datetimemax LLCONST(315537897600000) // max. allowed number for datetime type
+#define _unixepoch LLCONST(62135596800000) // difference between time_t and datetime in milliseconds
+
+
+// datetime general utilities
+inline int days(datetime d) { return int(d / _msecsmax); }
+inline int msecs(datetime d) { return int(d % _msecsmax); }
+
+ptpublic datetime ptdecl mkdt(int days, int msecs);
+ptpublic bool ptdecl isvalid(datetime);
+ptpublic datetime ptdecl now(bool utc = true);
+ptpublic void ptdecl tzupdate();
+ptpublic int ptdecl tzoffset();
+ptpublic string ptdecl dttostring(datetime, const char* fmt);
+ptpublic string ptdecl nowstring(const char* fmt, bool utc = true);
+ptpublic datetime ptdecl utodatetime(time_t u);
+ptpublic struct tm* ptdecl dttotm(datetime dt, struct tm& t);
+
+// date/calendar manipulation
+ptpublic bool ptdecl isleapyear(int year);
+ptpublic int ptdecl daysinmonth(int year, int month);
+ptpublic int ptdecl daysinyear(int year, int month);
+ptpublic int ptdecl dayofweek(datetime);
+ptpublic bool ptdecl isdatevalid(int year, int month, int day);
+ptpublic datetime ptdecl encodedate(int year, int month, int day);
+ptpublic bool ptdecl decodedate(datetime, int& year, int& month, int& day);
+
+// time manipulation
+ptpublic bool ptdecl istimevalid(int hour, int min, int sec, int msec = 0);
+ptpublic datetime ptdecl encodetime(int hour, int min, int sec, int msec = 0);
+ptpublic bool ptdecl decodetime(datetime, int& hour, int& min, int& sec, int& msec);
+ptpublic bool ptdecl decodetime(datetime, int& hour, int& min, int& sec);
+
+
+PTYPES_END
+
+#endif // __PTIME_H__
diff --git a/include/ptypes/ptypes.h b/include/ptypes/ptypes.h
new file mode 100644
index 0000000..0769d45
--- /dev/null
+++ b/include/ptypes/ptypes.h
@@ -0,0 +1,1345 @@
+/*
+ *
+ * C++ Portable Types Library (PTypes)
+ * Version 2.1.1 Released 27-Jun-2007
+ *
+ * Copyright (C) 2001-2007 Hovik Melikyan
+ *
+ * http://www.melikyan.com/ptypes/
+ *
+ */
+
+#ifndef __PTYPES_H__
+#define __PTYPES_H__
+
+
+#ifndef __PPORT_H__
+#include "pport.h"
+#endif
+
+#include
+
+
+PTYPES_BEGIN
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 4)
+// disable "non dll-interface class '...' used as base for dll-interface class '...'" warning
+#pragma warning(disable : 4275)
+// disable "conditional expression constant" warning
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
+
+ptpublic int __PFASTCALL pincrement(int* target);
+ptpublic int __PFASTCALL pdecrement(int* target);
+ptpublic int __PFASTCALL pexchange(int* target, int value);
+ptpublic void* __PFASTCALL pexchange(void** target, void* value);
+
+template inline T* tpexchange(T** target, T* value)
+ { return (T*)pexchange((void**)target, (void*)value); }
+
+
+#if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ == 4) || defined(__hpux)
+# define VARIANT_TYPECAST_HACK
+#endif
+
+
+// -------------------------------------------------------------------- //
+// --- string class --------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+// dynamic string class with thread-safe ref-counted buffer
+
+struct _strrec
+{
+ int refcount;
+ int length;
+};
+typedef _strrec* _pstrrec;
+
+
+#define STR_BASE(x) (_pstrrec(x)-1)
+#define STR_REFCOUNT(x) (STR_BASE(x)->refcount)
+#define STR_LENGTH(x) (STR_BASE(x)->length)
+
+#define PTR_TO_PSTRING(p) (pstring(&(p)))
+#define PTR_TO_STRING(p) (*PTR_TO_PSTRING(p))
+
+
+ptpublic extern char* emptystr;
+
+class ptpublic variant;
+
+
+class ptpublic string
+{
+ friend class variant;
+
+protected:
+ char* data;
+
+ static void idxerror();
+
+ void _alloc(int);
+ void _realloc(int);
+ void _free();
+
+ void initialize() { data = emptystr; }
+ void initialize(const char*, int);
+ void initialize(const char*);
+ void initialize(char);
+ void initialize(const string& s);
+ void initialize(const char*, int, const char*, int);
+ void initialize(const variant&);
+ void finalize();
+
+ void assign(const char*, int);
+ void assign(const char*);
+ void assign(const string&);
+ void assign(char);
+
+#ifdef CHECK_BOUNDS
+ void idx(int index) const { if (unsigned(index) >= unsigned(STR_LENGTH(data))) idxerror(); }
+#else
+ void idx(int) const { }
+#endif
+
+ string(const char* s1, int len1, const char* s2, int len2) { initialize(s1, len1, s2, len2); }
+
+public:
+ friend int length(const string& s);
+ friend int refcount(const string& s);
+ friend void assign(string& s, const char* buf, int len);
+ friend void clear(string& s);
+ friend bool isempty(const string& s);
+ ptpublic friend char* ptdecl setlength(string&, int);
+ ptpublic friend char* ptdecl unique(string&);
+ ptpublic friend void ptdecl concat(string& s, const char* sc, int catlen);
+ ptpublic friend void ptdecl concat(string& s, const char* s1);
+ ptpublic friend void ptdecl concat(string& s, char s1);
+ ptpublic friend void ptdecl concat(string& s, const string& s1);
+ ptpublic friend string ptdecl copy(const string& s, int from, int cnt);
+ ptpublic friend string ptdecl copy(const string& s, int from);
+ ptpublic friend void ptdecl ins(const char* s1, int s1len, string& s, int at);
+ ptpublic friend void ptdecl ins(const char* s1, string& s, int at);
+ ptpublic friend void ptdecl ins(char s1, string& s, int at);
+ ptpublic friend void ptdecl ins(const string& s1, string& s, int at);
+ ptpublic friend void ptdecl del(string& s, int at, int cnt);
+ ptpublic friend void ptdecl del(string& s, int at);
+ ptpublic friend int ptdecl pos(const char* s1, const string& s);
+ ptpublic friend int ptdecl pos(char s1, const string& s);
+ friend int pos(const string& s1, const string& s);
+ ptpublic friend int ptdecl rpos(char s1, const string& s);
+ ptpublic friend bool ptdecl contains(const char* s1, int len, const string& s, int at);
+ ptpublic friend bool ptdecl contains(const char* s1, const string& s, int at);
+ ptpublic friend bool ptdecl contains(char s1, const string& s, int at);
+ ptpublic friend bool ptdecl contains(const string& s1, const string& s, int at);
+ ptpublic friend string ptdecl dup(const string& s);
+
+ string() { initialize(); }
+ string(const char* sc, int initlen) { initialize(sc, initlen); }
+ string(const char* sc) { initialize(sc); }
+ string(char c) { initialize(c); }
+ string(const string& s) { initialize(s); }
+ ~string() { finalize(); }
+
+#ifdef VARIANT_TYPECAST_HACK
+ string(const variant& v) { initialize(v); }
+#endif
+
+ string& operator= (const char* sc) { assign(sc); return *this; }
+ string& operator= (char c) { assign(c); return *this; }
+ string& operator= (const string& s) { assign(s); return *this; }
+ string& operator+= (const char* sc) { concat(*this, sc); return *this; }
+ string& operator+= (char c) { concat(*this, c); return *this; }
+ string& operator+= (const string& s) { concat(*this, s); return *this; }
+
+ string operator+ (const char* sc) const;
+ string operator+ (char c) const;
+ string operator+ (const string& s) const;
+
+ ptpublic friend string ptdecl operator+ (const char* sc, const string& s);
+ ptpublic friend string ptdecl operator+ (char c, const string& s);
+
+ bool operator== (const char* sc) const { return strcmp(data, sc) == 0; }
+ bool operator== (char) const;
+ bool operator== (const string&) const;
+ bool operator!= (const char* sc) const { return !(*this == sc); }
+ bool operator!= (char c) const { return !(*this == c); }
+ bool operator!= (const string& s) const { return !(*this == s); }
+
+ friend bool operator== (const char*, const string&);
+ friend bool operator== (char, const string&);
+ friend bool operator!= (const char*, const string&);
+ friend bool operator!= (char, const string&);
+
+ operator const char*() const { return data; }
+ operator const uchar*() const { return (uchar*)data; }
+
+ char& operator[] (int i) { idx(i); return unique(*this)[i]; }
+ const char& operator[] (int i) const { idx(i); return data[i]; }
+
+ friend void initialize(string& s);
+ friend void initialize(string& s, const string& s1);
+ friend void initialize(string& s, const char* s1);
+ friend void finalize(string& s);
+};
+
+
+typedef string* pstring;
+
+inline int length(const string& s) { return STR_LENGTH(s.data); }
+inline int refcount(const string& s) { return STR_REFCOUNT(s.data); }
+inline void assign(string& s, const char* buf, int len) { s.assign(buf, len); }
+inline void clear(string& s) { s.finalize(); }
+inline bool isempty(const string& s) { return length(s) == 0; }
+inline int pos(const string& s1, const string& s) { return pos(s1.data, s); }
+inline bool operator== (const char* sc, const string& s){ return s == sc; }
+inline bool operator== (char c, const string& s) { return s == c; }
+inline bool operator!= (const char* sc, const string& s){ return s != sc; }
+inline bool operator!= (char c, const string& s) { return s != c; }
+inline void initialize(string& s) { s.initialize(); }
+inline void initialize(string& s, const string& s1) { s.initialize(s1); }
+inline void initialize(string& s, const char* s1) { s.initialize(s1); }
+inline void finalize(string& s) { s.finalize(); }
+
+
+ptpublic extern int stralloc;
+
+ptpublic extern string nullstring;
+
+
+// -------------------------------------------------------------------- //
+// --- string utilities ----------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+ptpublic string ptdecl fill(int width, char pad);
+ptpublic string ptdecl pad(const string& s, int width, char c, bool left = true);
+
+ptpublic string ptdecl itostring(large value, int base, int width = 0, char pad = 0);
+ptpublic string ptdecl itostring(ularge value, int base, int width = 0, char pad = 0);
+ptpublic string ptdecl itostring(int value, int base, int width = 0, char pad = 0);
+ptpublic string ptdecl itostring(unsigned value, int base, int width = 0, char pad = 0);
+ptpublic string ptdecl itostring(large v);
+ptpublic string ptdecl itostring(ularge v);
+ptpublic string ptdecl itostring(int v);
+ptpublic string ptdecl itostring(unsigned v);
+
+ptpublic large ptdecl stringtoi(const char*);
+ptpublic large ptdecl stringtoie(const char*);
+ptpublic ularge ptdecl stringtoue(const char*, int base);
+
+ptpublic string ptdecl lowercase(const char* s);
+ptpublic string ptdecl lowercase(const string& s);
+
+char hex4(char c);
+
+inline char locase(char c)
+ { if (c >= 'A' && c <= 'Z') return char(c + 32); return c; }
+
+inline char upcase(char c)
+ { if (c >= 'a' && c <= 'z') return char(c - 32); return c; }
+
+inline int hstrlen(const char* p) // some Unix systems do not accept NULL
+ { return p == nil ? 0 : (int)strlen(p); }
+
+
+
+
+// -------------------------------------------------------------------- //
+// --- character set -------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+const int _csetbits = 256;
+const int _csetbytes = _csetbits / 8;
+const int _csetwords = _csetbytes / sizeof(int);
+const char _csetesc = '~';
+
+
+class ptpublic cset
+{
+protected:
+ char data[_csetbytes];
+
+ void assign(const cset& s) { memcpy(data, s.data, _csetbytes); }
+ void assign(const char* setinit);
+ void clear() { memset(data, 0, _csetbytes); }
+ void fill() { memset(data, -1, _csetbytes); }
+ void include(char b) { data[uchar(b) / 8] |= uchar(1 << (uchar(b) % 8)); }
+ void include(char min, char max);
+ void exclude(char b) { data[uchar(b) / 8] &= uchar(~(1 << (uchar(b) % 8))); }
+ void unite(const cset& s);
+ void subtract(const cset& s);
+ void intersect(const cset& s);
+ void invert();
+ bool contains(char b) const { return (data[uchar(b) / 8] & (1 << (uchar(b) % 8))) != 0; }
+ bool eq(const cset& s) const { return memcmp(data, s.data, _csetbytes) == 0; }
+ bool le(const cset& s) const;
+
+public:
+ cset() { clear(); }
+ cset(const cset& s) { assign(s); }
+ cset(const char* setinit) { assign(setinit); }
+
+ cset& operator= (const cset& s) { assign(s); return *this; }
+ cset& operator+= (const cset& s) { unite(s); return *this; }
+ cset& operator+= (char b) { include(b); return *this; }
+ cset operator+ (const cset& s) const { cset t = *this; return t += s; }
+ cset operator+ (char b) const { cset t = *this; return t += b; }
+ cset& operator-= (const cset& s) { subtract(s); return *this; }
+ cset& operator-= (char b) { exclude(b); return *this; }
+ cset operator- (const cset& s) const { cset t = *this; return t -= s; }
+ cset operator- (char b) const { cset t = *this; return t -= b; }
+ cset& operator*= (const cset& s) { intersect(s); return *this; }
+ cset operator* (const cset& s) const { cset t = *this; return t *= s; }
+ cset operator! () const { cset t = *this; t.invert(); return t; }
+ bool operator== (const cset& s) const { return eq(s); }
+ bool operator!= (const cset& s) const { return !eq(s); }
+ bool operator<= (const cset& s) const { return le(s); }
+ bool operator>= (const cset& s) const { return s.le(*this); }
+
+ friend cset operator+ (char b, const cset& s);
+ friend bool operator& (char b, const cset& s);
+ friend void assign(cset& s, const char* setinit);
+ friend void clear(cset& s);
+ friend void fill(cset& s);
+ friend void include(cset& s, char b);
+ friend void include(cset& s, char min, char max);
+ friend void exclude(cset& s, char b);
+
+ ptpublic friend string ptdecl asstring(const cset& s);
+};
+
+
+inline cset operator+ (char b, const cset& s) { return s + b; }
+inline bool operator& (char b, const cset& s) { return s.contains(b); }
+inline void assign(cset& s, const char* setinit) { s.assign(setinit); }
+inline void clear(cset& s) { s.clear(); }
+inline void fill(cset& s) { s.fill(); }
+inline void include(cset& s, char b) { s.include(b); }
+inline void include(cset& s, char min, char max) { s.include(min, max); }
+inline void exclude(cset& s, char b) { s.exclude(b); }
+
+
+// -------------------------------------------------------------------- //
+// --- basic abstract classes ----------------------------------------- //
+// -------------------------------------------------------------------- //
+
+// basic class with virtual destructor; historically was used as a base
+// for all list items. also helps to count the number of created and
+// destroyed objects in a program (objalloc global) in DEBUG mode, to
+// detect memory leaks. most classes in ptypes are derived from unknown.
+
+ptpublic extern int objalloc;
+
+class ptpublic unknown
+{
+private:
+ // make all classes non-copyable by default
+ unknown(const unknown&);
+ const unknown& operator= (const unknown&);
+public:
+#ifdef COUNT_OBJALLOC
+ unknown() { pincrement(&objalloc); }
+ virtual ~unknown() { pdecrement(&objalloc); }
+#else
+ unknown() { }
+ virtual ~unknown() { }
+#endif
+};
+
+typedef unknown* punknown;
+
+
+// provide non-copyable base for all classes that are
+// not derived from 'unknown'
+
+class ptpublic noncopyable
+{
+private:
+ noncopyable(const noncopyable&);
+ const noncopyable& operator= (const noncopyable&);
+public:
+ noncopyable() {}
+ ~noncopyable() {}
+};
+
+
+
+// -------------------------------------------------------------------- //
+// --- exception ------------------------------------------------------ //
+// -------------------------------------------------------------------- //
+
+// the basic exception class. NOTE: the library always throws dynamically
+// allocated exception objects.
+
+class ptpublic exception: public unknown
+{
+protected:
+ string message;
+public:
+ exception(const char* imsg);
+ exception(const string& imsg);
+ virtual ~exception();
+ virtual string get_message() { return message; }
+};
+
+
+// conversion exception class for stringtoie() and stringtoue()
+
+class ptpublic econv: public exception
+{
+public:
+ econv(const char* msg): exception(msg) {}
+ econv(const string& msg): exception(msg) {}
+ virtual ~econv();
+};
+
+
+// -------------------------------------------------------------------- //
+// --- tpodlist ------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+// _podlist implements dynamic array of small POD structures; it serves
+// as a basis for all list types in the library. this class is undocumented.
+// tpodlist template must be used instead.
+
+class _podlist: public noncopyable
+{
+protected:
+ void* list; // pointer to the array
+ int count; // number of items in the list
+ int capacity; // allocated for the list
+ int itemsize; // list item size
+
+/*#ifndef DEBUG
+ static
+#endif*/
+ static void idxerror();
+ //void idxerror() const { fatal(CRIT_FIRST + 30, "List index out of bounds"); }
+
+ _podlist& operator =(const _podlist& t);
+
+ void grow();
+ void* doins(int index);
+ void doins(int index, const _podlist&);
+ void* doget(int index) const { return (char*)list + index * itemsize; }
+ void dodel(int index);
+ void dodel(int index, int count);
+ void dopop();
+
+#ifdef CHECK_BOUNDS
+ void idx(int index) const { if (unsigned(index) >= unsigned(count)) idxerror(); }
+ void idxa(int index) const { if (unsigned(index) > unsigned(count)) idxerror(); }
+#else
+ void idx(int) const { }
+ void idxa(int) const { }
+#endif
+
+public:
+ _podlist(int itemsize);
+ ~_podlist();
+
+ int get_count() const { return count; }
+ void set_count(int newcount, bool zero = false);
+ int get_capacity() const { return capacity; }
+ void set_capacity(int newcap);
+ void clear() { set_count(0); }
+ void pack() { set_capacity(count); }
+ void* ins(int index) { idxa(index); return doins(index); }
+ void ins(int index, const _podlist& t) { idxa(index); doins(index, t); }
+ void* add();
+ void add(const _podlist& t);
+ void* operator [](int index) { idx(index); return doget(index); }
+ void* top() { return operator [](count - 1); }
+ void del(int index) { idx(index); dodel(index); }
+ void del(int index, int count) { idx(index); dodel(index, count); }
+ void pop() { idx(0); dopop(); }
+};
+
+
+// tpodlist is a fully-inlined template based on _podlist
+
+template class ptpublic tpodlist: public _podlist
+{
+protected:
+ X& dozero(X& t) { if (initzero) memset(&t, 0, sizeof(X)); return t; }
+ X& doget(int index) const { return ((X*)list)[index]; }
+ X& doins(int index) { X& t = *(X*)_podlist::doins(index); return dozero(t); }
+ void doins(int index, const X& item) { *(X*)_podlist::doins(index) = item; }
+
+public:
+ tpodlist(): _podlist(sizeof(X)) {}
+ tpodlist& operator =(const tpodlist& t)
+ { _podlist::operator =(t); return *this; }
+ ~tpodlist() { }
+
+ void set_count(int newcount) { _podlist::set_count(newcount, initzero); }
+ X& ins(int index) { idxa(index); return doins(index); }
+ void ins(int index, const X& item) { idxa(index); doins(index, item); }
+ void ins(int index, const tpodlist& t)
+ { _podlist::ins(index, t); }
+ X& add() { grow(); return dozero(doget(count++)); }
+ void add(const X& item) { grow(); doget(count++) = item; }
+ void add(const tpodlist& t)
+ { _podlist::add(t); }
+ X& operator [](int index) { idx(index); return doget(index); }
+ const X& operator [](int index) const { idx(index); return doget(index); }
+ X& top() { idx(0); return doget(count - 1); }
+};
+
+
+// -------------------------------------------------------------------- //
+// --- tobjlist ------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+// _objlist is a base for the tobjlist template, don't use it directly.
+// also, _objlist is a base for _strlist and derivatives.
+
+class ptpublic _objlist: public unknown, protected tpodlist
+{
+protected:
+ struct
+ {
+ unsigned ownobjects :1; // list is responsible for destroying the items; used in _objlist
+ unsigned ownslobjects :1; // same but for _strlist items (in _stritem structure)
+ unsigned sorted :1; // sorted list (_objlist+)
+ unsigned duplicates :1; // sorted: allows duplicate keys (_objlist+)
+ unsigned casesens :1; // sorted: string comparison is case sensitive (_strlist+)
+ unsigned _reserved :27;
+ } config;
+
+ _objlist(bool ownobjects); // we hide this ctor, since _objlist actually can't free objects
+
+ void* doget(int index) const { return ((void**)list)[index]; }
+ void doput(int index, void* obj);
+ void dodel(int index);
+ void dodel(int index, int count);
+ void* dopop();
+ void dofree(int index, int count);
+
+ virtual void dofree(void* obj); // pure method; defined in tobjlist instances
+ virtual int compare(const void* key, const void* obj) const; // pure method; defined in _strlist
+
+public:
+ _objlist();
+ virtual ~_objlist();
+
+ int get_count() const { return count; }
+ void set_count(int newcount);
+ int get_capacity() const { return capacity; }
+ void set_capacity(int newcap) { tpodlist::set_capacity(newcap); }
+ void clear() { set_count(0); }
+ void pack() { tpodlist::pack(); }
+ void ins(int index, void* obj) { tpodlist::ins(index, obj); }
+ void add(void* obj) { tpodlist::add(obj); }
+ void put(int index, void* obj) { idx(index); doput(index, obj); }
+ void* operator [](int index) const { idx(index); return doget(index); }
+ void* top() const { idx(0); return doget(count - 1); }
+ void* pop() { idx(0); return dopop(); }
+ void del(int index) { idx(index); dodel(index); }
+ void del(int index, int count) { idx(index); dodel(index, count); }
+ int indexof(void* obj) const;
+ bool search(const void* key, int& index) const;
+};
+
+
+// the tobjlist template implements a list of pointers to arbitrary
+// structures. optionally can automatically free objects (ownobjects)
+// when removed from a list. only 2 virtual functions are being
+// instantiated by this template, the rest is static code in _objlist.
+
+template class tobjlist: public _objlist
+{
+protected:
+ X* doget(int index) const { return (X*)_objlist::doget(index); }
+ virtual void dofree(void* obj);
+
+public:
+ tobjlist(bool ownobjects = false): _objlist(ownobjects) {}
+ virtual ~tobjlist();
+
+ bool get_ownobjects() const { return config.ownobjects; }
+ void set_ownobjects(bool newval) { config.ownobjects = newval; }
+ void ins(int index, X* obj) { _objlist::ins(index, obj); }
+ void add(X* obj) { _objlist::add(obj); }
+ void put(int index, X* obj) { _objlist::put(index, obj); }
+ X* operator [](int index) const { idx(index); return (X*)doget(index); }
+ X* top() const { return (X*)_objlist::top(); }
+ X* pop() { return (X*)_objlist::pop(); }
+ int indexof(X* obj) const { return _objlist::indexof(obj); }
+
+#ifdef PTYPES19_COMPAT
+ friend inline void ins(tobjlist& s, int i, X* obj) { s.ins(i, obj); }
+ friend inline int add(tobjlist& s, X* obj) { s.add(obj); return s.get_count() - 1; }
+ friend inline void put(tobjlist& s, int i, X* obj) { s.put(i, obj); }
+ friend inline int indexof(const tobjlist& s, X* obj) { return s.indexof(obj); }
+ friend inline int push(tobjlist& s, X* obj) { s.add(obj); return s.get_count() - 1; }
+ friend inline X* pop(tobjlist& s) { return (X*)s.pop(); }
+ friend inline X* top(const tobjlist& s) { return (X*)s.top(); }
+ friend inline X* get(const tobjlist& s, int i) { return (X*)s[i]; }
+#endif
+};
+
+
+template void tobjlist::dofree(void* item)
+{
+ delete (X*)item;
+}
+
+
+template tobjlist::~tobjlist()
+{
+ set_count(0);
+}
+
+
+// -------------------------------------------------------------------- //
+// --- tstrlist ------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+// _strlist is a base for the tstrlist template
+
+
+typedef int slflags; // left for compatibility
+
+#define SL_SORTED 1
+#define SL_DUPLICATES 2
+#define SL_CASESENS 4
+#define SL_OWNOBJECTS 8
+
+
+struct _stritem
+{
+ string key;
+ void* obj;
+
+ _stritem(const string& ikey, void* iobj)
+ : key(ikey), obj(iobj) {}
+};
+
+
+class ptpublic _strlist: protected tobjlist<_stritem>
+{
+protected:
+ static void sortederror();
+ static void notsortederror();
+ static void duperror();
+
+ virtual void dofree(void* item);
+ virtual int compare(const void* key, const void* item) const;
+ virtual void dofreeobj(void* obj); // pure; tstrlist overrides it
+
+ const string& dogetkey(int index) const { return doget(index)->key; }
+ void* dogetobj(int index) const { return doget(index)->obj; }
+ void doins(int index, const string& key, void* obj);
+ void doput(int index, const string& key, void* obj);
+ void doput(int index, void* obj);
+
+public:
+ _strlist(int flags = 0);
+ virtual ~_strlist();
+
+ int get_count() const { return count; }
+ void set_count(int newcount) { tobjlist<_stritem>::set_count(newcount); }
+ int get_capacity() const { return capacity; }
+ void set_capacity(int newcap) { tobjlist<_stritem>::set_capacity(newcap); }
+ void clear() { tobjlist<_stritem>::clear(); }
+ void pack() { tobjlist<_stritem>::pack(); }
+ bool get_sorted() const { return config.sorted; }
+ bool get_duplicates() const { return config.duplicates; }
+ bool get_casesens() const { return config.casesens; }
+ bool get_ownobjects() const { return config.ownslobjects; }
+ void set_ownobjects(bool newval) { config.ownslobjects = newval; }
+ void ins(int index, const string& key, void* obj) { idxa(index); doins(index, key, obj); }
+ void put(int index, const string& key, void* obj) { idx(index); doput(index, key, obj); }
+ void put(int index, void* obj) { idx(index); doput(index, obj); }
+ int put(const string& key, void* obj);
+ int add(const string& key, void* obj);
+ void* operator [](int index) const { idx(index); return dogetobj(index); }
+ void* operator [](const char* key) const;
+ const string& getkey(int index) const { idx(index); return dogetkey(index); }
+ bool search(const char* key, int& index) const { return _objlist::search(key, index); }
+ void del(int index) { idx(index); dodel(index); }
+ void del(int index, int delcount) { idx(index); dodel(index, delcount); }
+ void del(const char* key) { put(key, nil); }
+ int indexof(const char* key) const;
+ int indexof(void* obj) const;
+};
+
+
+// the tstrlist template implements a list of string/object pairs,
+// optionally sorted for fast searching by string key.
+
+template class tstrlist: public _strlist
+{
+protected:
+ virtual void dofreeobj(void* obj);
+
+public:
+ tstrlist(int flags = 0): _strlist(flags) {}
+ virtual ~tstrlist();
+
+ void ins(int index, const string& key, X* obj) { _strlist::ins(index, key, obj); }
+ void put(int index, const string& key, X* obj) { _strlist::put(index, key, obj); }
+ void put(int index, X* obj) { _strlist::put(index, obj); }
+ int put(const string& key, X* obj) { return _strlist::put(key, obj); }
+ int add(const string& key, X* obj) { return _strlist::add(key, obj); }
+ X* operator [](int index) const { return (X*)_strlist::operator [](index); }
+ X* operator [](const char* key) const { return (X*)_strlist::operator [](key); }
+ int indexof(X* obj) const { return _strlist::indexof(obj); }
+ int indexof(const char* key) const { return _strlist::indexof(key); }
+
+#ifdef PTYPES19_COMPAT
+ // pre-2.0 interface for backwards compatibility
+ friend inline void ins(tstrlist& s, int i, const string& str, X* obj) { s.ins(i, str, obj); }
+ friend inline int add(tstrlist& s, const string& str, X* obj) { return s.add(str, obj); }
+ friend inline void put(tstrlist& s, int i, const string& str, X* obj) { s.put(i, str, obj); }
+ friend inline void put(tstrlist& s, int i, X* obj) { s.put(i, obj); }
+ friend inline int indexof(const tstrlist& s, X* obj) { return s.indexof(obj); }
+ friend inline X* get(const tstrlist& s, int i) { return (X*)s[i]; }
+#endif
+};
+
+
+template void tstrlist::dofreeobj(void* obj)
+{
+ delete (X*)obj;
+}
+
+
+template tstrlist::~tstrlist()
+{
+ set_count(0);
+}
+
+
+// -------------------------------------------------------------------- //
+// --- textmap -------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+// textmap is a list of string pairs (key/value)
+
+struct _textitem
+{
+ string key;
+ string value;
+
+ _textitem(const string& ikey, const string& ivalue)
+ : key(ikey), value(ivalue) {}
+};
+
+
+class ptpublic textmap: protected tobjlist<_textitem>
+{
+protected:
+ virtual int compare(const void* key, const void* item) const;
+ const string& dogetvalue(int index) const { return doget(index)->value; }
+ const string& dogetkey(int index) const { return doget(index)->key; }
+
+public:
+ textmap(bool casesens = false);
+ virtual ~textmap();
+
+ int get_count() const { return tobjlist<_textitem>::get_count(); }
+ void pack() { tobjlist<_textitem>::pack(); }
+ void clear() { tobjlist<_textitem>::clear(); }
+ int put(const string& key, const string& value);
+ void del(int index) { idx(index); dodel(index); }
+ void del(const char* key) { put(key, nullstring); }
+ const string& get(int index) const { idx(index); return dogetvalue(index); }
+ const string& getkey(int index) const { idx(index); return dogetkey(index); }
+ const string& get(const char* key) const;
+ const string& operator [](int index) const { return get(index); }
+ const string& operator [](const char* key) const { return get(key); }
+ int indexof(const char* key) const;
+};
+
+
+// -------------------------------------------------------------------- //
+// --- component ------------------------------------------------------ //
+// -------------------------------------------------------------------- //
+
+// the component class is an abstract class that provides reference
+// counting and delete notification mechanisms. all stream classes
+// in ptypes are derived from component.
+
+// class ID's for all basic types: the first byte (least significant)
+// contains the base ID, the next is for the second level of inheritance,
+// etc. total of 4 levels allowed for basic types. call classid() for an
+// object, mask out first N bytes of interest and compare with a CLASS_XXX
+// value. f.ex. to determine whether an object is of type infile or any
+// derivative: (o->classid() & 0xffff) == CLASS2_INFILE. this scheme is for
+// internal use by PTypes and Objection; partly replaces the costly C++ RTTI
+// system.
+
+// first level of inheritance
+const int CLASS_UNDEFINED = 0x00000000;
+const int CLASS_INSTM = 0x00000001;
+const int CLASS_OUTSTM = 0x00000002;
+const int CLASS_UNIT = 0x00000003;
+
+// second level of inheritance
+const int CLASS2_INFILE = 0x00000100 | CLASS_INSTM;
+const int CLASS2_INMEMORY = 0x00000200 | CLASS_INSTM;
+const int CLASS2_FDX = 0x00000300 | CLASS_INSTM;
+const int CLASS2_OUTFILE = 0x00000100 | CLASS_OUTSTM;
+const int CLASS2_OUTMEMORY = 0x00000200 | CLASS_OUTSTM;
+
+// third level of inheritance
+const int CLASS3_LOGFILE = 0x00010000 | CLASS2_OUTFILE;
+const int CLASS3_IPSTM = 0x00020000 | CLASS2_FDX;
+const int CLASS3_NPIPE = 0x00030000 | CLASS2_FDX;
+
+
+class ptpublic component: public unknown
+{
+protected:
+ int refcount; // reference counting, used by addref() and release()
+ tobjlist* freelist; // list of components to notify about destruction, safer alternative to ref-counting
+ void* typeinfo; // reserved for future use
+
+ virtual void freenotify(component* sender);
+
+public:
+ component();
+ virtual ~component();
+ void addnotification(component* obj);
+ void delnotification(component* obj);
+
+ ptpublic friend component* ptdecl addref(component*);
+ ptpublic friend bool ptdecl release(component*);
+ friend int refcount(component* c);
+
+ virtual int classid();
+
+ void set_typeinfo(void* t) { typeinfo = t; }
+ void* get_typeinfo() { return typeinfo; }
+};
+
+typedef component* pcomponent;
+
+
+inline int refcount(component* c) { return c->refcount; }
+
+
+template inline T* taddref(T* c)
+ { return (T*)addref((component*)c); }
+
+
+template class compref
+{
+protected:
+ T* ref;
+public:
+ compref() { ref = 0; }
+ compref(const compref& r) { ref = taddref(r.ref); }
+ compref(T* c) { ref = taddref(c); }
+ ~compref() { release(ref); }
+ compref& operator =(T* c);
+ compref& operator =(const compref& r) { return operator =(r.ref); }
+ T& operator *() const { return *ref; }
+ T* operator ->() const { return ref; }
+ bool operator ==(const compref& r) const { return ref == r.ref; }
+ bool operator ==(T* c) const { return ref == c; }
+ bool operator !=(const compref& r) const { return ref != r.ref; }
+ bool operator !=(T* c) const { return ref != c; }
+ operator T*() const { return ref; }
+};
+
+
+template compref& compref::operator =(T* c)
+{
+ release(tpexchange(&ref, taddref(c)));
+ return *this;
+}
+
+
+// -------------------------------------------------------------------- //
+// --- variant -------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+enum {
+ VAR_NULL,
+ VAR_INT,
+ VAR_BOOL,
+ VAR_FLOAT,
+ VAR_STRING,
+ VAR_ARRAY,
+ VAR_OBJECT,
+
+ VAR_COMPOUND = VAR_STRING
+};
+
+
+class ptpublic _varray;
+
+
+class ptpublic variant
+{
+ friend class string;
+ friend class _varray;
+
+protected:
+ int tag; // VAR_XXX
+ union {
+ large i; // 64-bit int value
+ bool b; // bool value
+ double f; // double value
+ char* s; // string object; can't declare as string because of the union
+ _varray* a; // pointer to a reference-counted _strlist object
+ component* o; // pointer to a reference-counted component object (or derivative)
+ } value; // we need this name to be able to copy the entire union in some situations
+
+ void initialize() { tag = VAR_NULL; }
+ void initialize(large v) { tag = VAR_INT; value.i = v; }
+ void initialize(bool v) { tag = VAR_BOOL; value.b = v; }
+ void initialize(double v) { tag = VAR_FLOAT; value.f = v; }
+ void initialize(const char* v) { tag = VAR_STRING; PTYPES_NAMESPACE::initialize(PTR_TO_STRING(value.s), v); }
+ void initialize(const string& v) { tag = VAR_STRING; PTYPES_NAMESPACE::initialize(PTR_TO_STRING(value.s), v); }
+ void initialize(_varray* a);
+ void initialize(component* o);
+ void initialize(const variant& v);
+ void finalize();
+
+ void assign(large);
+ void assign(bool);
+ void assign(double);
+ void assign(const char*);
+ void assign(const string&);
+ void assign(_varray*);
+ void assign(component*);
+ void assign(const variant&);
+
+ bool equal(const variant& v) const;
+
+ variant(_varray* a) { initialize(a); }
+
+public:
+ // construction
+ variant() { initialize(); }
+ variant(int v) { initialize(large(v)); }
+ variant(unsigned int v) { initialize(large(v)); }
+ variant(large v) { initialize(v); }
+ variant(bool v) { initialize(v); }
+ variant(double v) { initialize(v); }
+ variant(const char* v) { initialize(v); }
+ variant(const string& v) { initialize(v); }
+ variant(component* v) { initialize(v); }
+ variant(const variant& v) { initialize(v); }
+ ~variant() { finalize(); }
+
+ // assignment
+ variant& operator= (int v) { assign(large(v)); return *this; }
+ variant& operator= (unsigned int v) { assign(large(v)); return *this; }
+ variant& operator= (large v) { assign(v); return *this; }
+ variant& operator= (bool v) { assign(v); return *this; }
+ variant& operator= (double v) { assign(v); return *this; }
+ variant& operator= (const char* v) { assign(v); return *this; }
+ variant& operator= (const string& v) { assign(v); return *this; }
+ variant& operator= (component* v) { assign(v); return *this; }
+ variant& operator= (const variant& v) { assign(v); return *this; }
+
+ // typecast
+ operator int() const;
+ operator unsigned int() const;
+ operator long() const;
+ operator unsigned long() const;
+ operator large() const;
+ operator bool() const;
+ operator double() const;
+ operator string() const;
+ operator component*() const;
+
+ // comparison
+ bool operator== (const variant& v) const { return equal(v); }
+ bool operator!= (const variant& v) const { return !equal(v); }
+
+ // typification
+ ptpublic friend void ptdecl clear(variant&);
+ friend int vartype(const variant& v);
+ friend bool isnull(const variant& v);
+ friend bool isint(const variant& v);
+ friend bool isbool(const variant& v);
+ friend bool isfloat(const variant& v);
+ friend bool isstring(const variant& v);
+ friend bool isarray(const variant& v);
+ friend bool isobject(const variant& v);
+ friend bool iscompound(const variant& v);
+
+ // array manipulation
+ ptpublic friend void ptdecl aclear(variant&);
+ ptpublic friend variant ptdecl aclone(const variant&);
+ ptpublic friend const variant& ptdecl get(const variant&, const string& key);
+ ptpublic friend const variant& ptdecl get(const variant&, large key);
+ ptpublic friend void ptdecl put(variant&, const string& key, const variant& item);
+ ptpublic friend void ptdecl put(variant&, large key, const variant& item);
+ ptpublic friend void ptdecl del(variant&, const string& key);
+ ptpublic friend void ptdecl del(variant&, large key);
+ ptpublic friend void ptdecl add(variant & v, const variant & var);
+
+ // indexed access to arrays
+ ptpublic friend int ptdecl alength(const variant&);
+ ptpublic friend void ptdecl apack(variant&);
+ ptpublic friend bool ptdecl anext(const variant& a, int&, variant& item);
+ ptpublic friend bool ptdecl anext(const variant& a, int&, variant& item, string& key);
+ ptpublic friend bool ptdecl anext(const variant& array, int& index, variant& item, variant & key);
+ ptpublic friend int ptdecl aadd(variant&, const variant& item);
+ ptpublic friend void ptdecl aput(variant&, int index, const variant& item);
+ ptpublic friend void ptdecl ains(variant&, int index, const variant& item);
+ ptpublic friend void ptdecl adel(variant&, int index);
+ ptpublic friend const variant& ptdecl aget(const variant&, int index);
+ ptpublic friend string ptdecl akey(const variant&, int index);
+
+ const variant& operator[](const char* key) const { return get(*this, string(key)); }
+ const variant& operator[](const string& key) const { return get(*this, key); }
+ const variant& operator[](large key) const { return get(*this, key); }
+
+ // 'manual' initialization/finalization, undocumented. use with care!
+ friend void initialize(variant& v);
+ friend void initialize(variant& v, large i);
+ friend void initialize(variant& v, int i);
+ friend void initialize(variant& v, unsigned int i);
+ friend void initialize(variant& v, bool i);
+ friend void initialize(variant& v, double i);
+ friend void initialize(variant& v, const char* i);
+ friend void initialize(variant& v, const string& i);
+ friend void initialize(variant& v, component* i);
+ friend void initialize(variant& v, const variant& i);
+ friend void finalize(variant& v);
+};
+
+
+typedef variant* pvariant;
+
+
+inline int vartype(const variant& v) { return v.tag; }
+inline bool isnull(const variant& v) { return v.tag == VAR_NULL; }
+inline bool isint(const variant& v) { return v.tag == VAR_INT; }
+inline bool isbool(const variant& v) { return v.tag == VAR_BOOL; }
+inline bool isfloat(const variant& v) { return v.tag == VAR_FLOAT; }
+inline bool isstring(const variant& v) { return v.tag == VAR_STRING; }
+inline bool isarray(const variant& v) { return v.tag == VAR_ARRAY; }
+inline bool isobject(const variant& v) { return v.tag == VAR_OBJECT; }
+inline bool iscompound(const variant& v) { return v.tag >= VAR_COMPOUND; }
+
+inline void initialize(variant& v) { v.initialize(); }
+inline void initialize(variant& v, large i) { v.initialize(i); }
+inline void initialize(variant& v, int i) { v.initialize(large(i)); }
+inline void initialize(variant& v, unsigned int i) { v.initialize(large(i)); }
+inline void initialize(variant& v, bool i) { v.initialize(i); }
+inline void initialize(variant& v, double i) { v.initialize(i); }
+inline void initialize(variant& v, const char* i) { v.initialize(i); }
+inline void initialize(variant& v, const string& i) { v.initialize(i); }
+inline void initialize(variant& v, component* i) { v.initialize(i); }
+inline void initialize(variant& v, const variant& i) { v.initialize(i); }
+inline void finalize(variant& v) { if (v.tag >= VAR_COMPOUND) v.finalize(); }
+
+
+ptpublic extern const variant nullvar;
+
+
+// variant exception class; may be thrown when a variant
+// is being typecast'ed to 32-bit int and the value is
+// out of range
+
+class ptpublic evariant: public exception
+{
+protected:
+public:
+ evariant(const char* msg): exception(msg) {}
+ evariant(const string& msg): exception(msg) {}
+ virtual ~evariant();
+};
+
+/*
+Added by Nathan Adams - the following is not apart of the original ptypes
+*/
+
+enum {
+ ARR_ASSOCIATIVE,
+ ARR_LIST,
+ ARR_NULL
+};
+
+/*
+ The reason for a tparray is that while a variant can be an
+ associative array - it stores numeric keys as hex strings
+ this can be very problematic if you want to loop through
+ all the elements and know if a given key was a number.
+ (For example for JSON encoding)
+
+ A tparray uses a variant for both the keys/values so
+ this really opens it up to a wide range of uses. Also,
+ it performs no conversions on the data so when you loop
+ through all the keys/vals they are what you stored them as.
+
+ This object's complexity is O(n) and it could in theory be better
+ by sectioning off the arrays such that
+ -------------------------------------------------------
+ | string | string | string | number | number | number |
+ -------------------------------------------------------
+ This would increase the complexity of adding items, and
+ if you don't have a very diverse number of items them you
+ may not benefit much from the algorithm.
+
+*/
+class ptpublic tparray : public component
+{
+protected:
+ int tag;
+ // using a tpodlist was causing variant data corrupt errors
+ // perhaps it has to do with the issue of the converting to pointers
+ // TODO: Write dynamic array class
+ //std::vector _keys;
+ //std::vector _vals;
+ variant _keys;
+ variant _vals;
+ //tpodlist _keys;
+ //tpodlist _vals;
+public:
+ static const void * TYPE; //declared in ptparray.cxx - http://stackoverflow.com/questions/1639154/how-to-declare-a-static-const-char-in-your-header-file
+ tparray() { typeinfo = const_cast(TYPE); tag = ARR_NULL; }
+ //anext function acts similar for variants and loops through elements
+
+ // This is allowed for both types
+ ptpublic friend bool ptdecl anext(const tparray& a, int& i, variant& val);
+
+ // This is only allowed for Associative arrays as a list doesn't have keys
+ ptpublic friend bool ptdecl anext(const tparray& a, int& i, variant& val, variant & key);
+
+ /*
+ Initialy the object will be NULL - but calling one of these functions
+ will change the type (permanently)
+ */
+ ptpublic friend void ptdecl add(tparray & t, const variant & val);
+ ptpublic friend void ptdecl add(tparray & t, const variant & key, const variant & val);
+
+ // get will perform a O(n) search for the matching variant in the keys array
+ ptpublic friend variant ptdecl get(tparray & t, const variant & val);
+
+ // This will return the value at the given index
+ ptpublic friend variant ptdecl at(tparray & t, large index);
+
+ // This will return the key at the given index
+ ptpublic friend variant ptdecl keyat(tparray & t, large index);
+
+ friend bool isassoc(const tparray& t);
+ friend bool islist(const tparray& t);
+ friend bool isnull(const tparray& t);
+};
+
+inline bool isassoc(const tparray& t) { return t.tag == ARR_ASSOCIATIVE; }
+inline bool islist(const tparray& t) { return t.tag == ARR_LIST; }
+inline bool isnull(const tparray& t) { return t.tag == ARR_NULL; }
+
+
+//http://stackoverflow.com/a/7936901/195722
+template class ByRef {
+public:
+ ByRef() {
+ }
+
+ ByRef(const T value) : mValue(value) {
+ }
+
+ operator T&() const {
+ return((T&)mValue);
+ }
+
+private:
+ T mValue;
+};
+
+
+class json
+{
+
+ protected:
+ string ParseString(const string & json, int & index, bool & success);
+ large ParseNumber(const string & json, int & index, bool & success);
+#ifndef USE_VARIANT
+ tparray * ParseObject(const string & json, int & index, bool & success);
+ tparray * ParseArray(const string & json, int & index, bool & success);
+#else
+ variant ParseObject(const string & json, int & index, bool & success);
+ variant ParseArray(const string & json, int & index, bool & success);
+#endif
+ int GetLastIndexOfNumber(const string & json, int index);
+ variant ParseValue(const string & json, int & index, bool & success);
+ int LookAhead(const string & json, int index);
+ void EatWhiteSpace(const string & json, int & index);
+ int NextToken(const string & json, int & index);
+ bool SerializeValue(const variant & value, string & builder);
+ bool SerializeString(const string & aString, string & builder);
+ bool SerializeObject(const tparray & anObject, string & builder);
+ bool SerializeArray(const tparray & anArray, string & builder);
+ bool SerializeNumber(large number, string & builder);
+ public:
+ enum Token { TOKEN_NONE,
+ TOKEN_CURLY_OPEN,
+ TOKEN_CURLY_CLOSE,
+ TOKEN_SQUARED_OPEN,
+ TOKEN_SQUARED_CLOSE,
+ TOKEN_COLON,
+ TOKEN_COMMA,
+ TOKEN_STRING,
+ TOKEN_NUMBER,
+ TOKEN_TRUE,
+ TOKEN_FALSE,
+ TOKEN_NULL };
+ variant JsonDecode(const string & json, bool & success = ByRef(true));
+ string JsonEncode(const variant & v);
+
+};
+
+class Parameter : public component
+{
+public:
+ string longparameter;
+ string shortparameter;
+ int numberofparameters;
+ bool required;
+ string hint;
+ Parameter(string longpara, string shortpara, string hint, bool required = false, int numberofparameters = 0)
+ {
+ this->longparameter = longpara;
+ this->shortparameter = shortpara;
+ this->hint = hint;
+ this->required = required;
+ this->numberofparameters = numberofparameters;
+ }
+};
+
+class pparser
+{
+ private:
+ variant choices;
+ //char * argv;
+ tobjlist * paras;
+ tobjlist argv;
+ tobjlist invalidparas;
+ tobjlist missingparas;
+ bool checkreq;
+ public:
+ pparser(int argc, char * argv[], const tobjlist & parameters);
+
+ void printusage(const char * header, const char * pname, const char * footer);
+
+ // Checks to make sure all required parameters are set
+ bool check() { return this->checkreq; }
+
+ // Returns true if parameter is set
+ bool isparameterset(const Parameter * para);
+
+ // Gets an array of variants of all the options to the parameters
+ // A variant will make it easier to convert to an int or another type
+ variant getoptions(const Parameter * para);
+};
+
+// -------------------------------------------------------------------- //
+// --- pre-2.0 compatibility declarations ----------------------------- //
+// -------------------------------------------------------------------- //
+
+
+#ifdef PTYPES19_COMPAT
+
+// ptypes-1.9 objlist and strlist: accept only 'unknown' and
+// derivatives as a base type
+
+class ptpublic objlist: public tobjlist
+{
+public:
+ objlist(bool ownobjects = false);
+ virtual ~objlist();
+};
+
+inline int length(const _objlist& s) { return s.get_count(); }
+inline void setlength(_objlist& s, int newcount) { s.set_count(newcount); }
+inline void pack(_objlist& s) { s.pack(); }
+inline void clear(_objlist& s) { s.clear(); }
+inline int push(_objlist& s, unknown* obj) { s.add(obj); return length(s) - 1; }
+inline unknown* top(const _objlist& s) { return (unknown*)s.top(); }
+inline void ins(_objlist& s, int i, unknown* obj) { s.ins(i, obj); }
+inline int add(_objlist& s, unknown* obj) { s.add(obj); return length(s) - 1; }
+inline void put(_objlist& s, int i, unknown* obj) { s.put(i, obj); }
+inline unknown* get(const _objlist& s, int i) { return (unknown*)s[i]; }
+inline unknown* pop(_objlist& s) { return (unknown*)s.pop(); }
+inline void del(_objlist& s, int i) { s.del(i); }
+inline int indexof(const _objlist& s, unknown* obj) { return s.indexof(obj); }
+
+
+class ptpublic strlist: public tstrlist
+{
+public:
+ strlist(int flags = 0);
+ virtual ~strlist();
+};
+
+inline int length(const _strlist& s) { return s.get_count(); }
+inline void clear(_strlist& s) { s.clear(); }
+inline void pack(_strlist& s) { s.pack(); }
+inline bool search(const _strlist& s, const char* key, int& i) { return s.search(key, i); }
+inline void ins(_strlist& s, int i, const string& key, unknown* obj) { s.ins(i, key, obj); }
+inline int add(_strlist& s, const string& key, unknown* obj) { return s.add(key, obj); }
+inline void put(_strlist& s, int i, const string& key, unknown* obj) { s.put(i, key, obj); }
+inline void put(_strlist& s, int i, unknown* obj) { s.put(i, obj); }
+inline unknown* get(const _strlist& s, int i) { return (unknown*)s[i]; }
+inline const string& getstr(const _strlist& s, int i) { return s.getkey(i); }
+inline void del(_strlist& s, int i) { s.del(i); }
+inline int find(const _strlist& s, const char* key) { return s.indexof(key); }
+inline int indexof(const _strlist& s, unknown* obj) { return s.indexof(obj); }
+
+
+// ptypes-1.9 strmap: now replaced with _strlist(SL_SORTED)
+
+class ptpublic strmap: public tstrlist
+{
+public:
+ strmap(int flags = 0);
+ virtual ~strmap();
+};
+
+inline void put(strmap& m, const string& key, unknown* obj) { m.put(key, obj); }
+inline unknown* get(const strmap& m, const char* key) { return m[key]; }
+inline void del(strmap& m, const char* key) { m.del(key); }
+
+template class tstrmap: public strmap
+{
+public:
+ tstrmap(): strmap() {}
+ tstrmap(int iflags): strmap(iflags) {}
+ friend inline X* get(const tstrmap& m, const char* str) { return (X*)PTYPES_NAMESPACE::get((const strmap&)m, str); }
+ friend inline void put(tstrmap& m, const string& str, X* obj) { unknown* t = obj; PTYPES_NAMESPACE::put(m, str, t); }
+ X* operator[] (const char* str) const { return (X*)PTYPES_NAMESPACE::get(*this, str); }
+};
+
+
+// ptypes-1.9 textmap interface
+
+inline int length(const textmap& m) { return m.get_count(); }
+inline void clear(textmap& m) { m.clear(); }
+inline const string& get(const textmap& m, const string& k) { return m.get(k); }
+inline void put(textmap& m, const string& k, const string& v) { m.put(k, v); }
+inline void del(textmap& m, const string& k) { m.del(k); }
+
+
+
+#endif // PTYPES19_COMPAT
+
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#pragma pack(pop)
+#endif
+
+
+PTYPES_END
+
+#endif // __PTYPES_H__
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..b639d34
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,157 @@
+#include
+#include
+#include
+#include
+
+USING_PTYPES;
+
+semaphore s(10);
+
+#define DEF_KEEP_ALIVE_TIMEOUT 15000
+
+void writeLog(ipaddress ip, string resp, string ask)
+{
+ const char * fmt = "%m-%d-%Y_%H:%M:%S";
+ string out = "[" + dttostring(now(), fmt) + " - " + iptostring(ip) + "] - " + ask + " => " + resp;
+ pout.putline(out);
+}
+
+void writeClient(ipstream * client, string msg)
+{
+ client->putline(msg);
+ client->flush();
+ writeLog(client->get_ip(), msg, "SERVER");
+}
+
+class ftp : public thread
+{
+ protected:
+ virtual void execute();
+ virtual void cleanup() { delete stream; }
+private:
+ ipstream * stream;
+ void commands();
+public:
+ ftp(ipstream * client) : thread(true), stream(client) { }
+};
+
+void ftp::commands()
+{
+ while(true)
+ {
+ if (!stream->get_active())
+ break;
+ if (!stream->waitfor(DEF_KEEP_ALIVE_TIMEOUT))
+ break;
+ if (stream->get_eof())
+ break;
+ string s;
+ s = stream->line(256);
+ writeLog(stream->get_ip(), s, "REQUEST");
+ if (lowercase(s) == "syst")
+ {
+ writeClient(stream, "215 UNIX Type: L8");
+ } else if ( lowercase(s) == "feat" )
+ {
+ writeClient(stream, "211-Features:");
+ writeClient(stream, "EPRT");
+ writeClient(stream, "EPSV");
+ writeClient(stream, "MDTM");
+ writeClient(stream, "PASV");
+ writeClient(stream, "REST STREAM");
+ writeClient(stream, "TVFS");
+ writeClient(stream, "UTF8");
+ writeClient(stream, "211 END");
+ } else if ( pos("TYPE", s) != -1 )
+ {
+ writeClient(stream, "200 Switching modes");
+ } else if ( lowercase(s) == "pwd")
+ {
+ writeClient(stream, "257 \"/\""); // root directory access oh yeah!
+ } else if ( pos("OPTS", s) != -1 )
+ {
+ writeClient(stream, "200 OK"); // hehe - accept setting any options
+ } else if ( lowercase(s) == "quit")
+ {
+ writeClient(stream, "215 goodbye");
+ break;
+ } else {
+ writeClient(stream, "200 OK"); // whatever you say client!
+ }
+ }
+}
+
+void ftp::execute()
+{
+ try
+ {
+ string s;
+ if (stream->get_active())
+ {
+ writeClient(stream, "220 ProFTPD 1.3.2c Server (datanethost.net_FTP_Service)");
+ // client enters username
+ s = stream->line(256);
+ writeLog(stream->get_ip(), s, "BANNER");
+
+ writeClient(stream, "330 Password required to access user account");
+
+ s = stream->line(256);
+ writeLog(stream->get_ip(), s, "PASSWORD");
+
+ writeClient(stream, "230 Logged in.");
+ commands();
+
+ }
+ } catch (estream * e)
+ {
+ pout.putline(e->get_message());
+ perr.putline("ERROR!");
+ delete e;
+ } catch (...)
+ {
+ perr.putline("ERROR2!");
+ }
+ stream->close();
+ s.signal();
+}
+
+class ftpthread : public thread, protected ipstmserver
+{
+ protected:
+ virtual void execute(); // override thread::execute()
+ virtual void cleanup() { } // override thread::cleanup()
+private:
+ int port;
+ tobjlist ftpworkers;
+ public:
+ ftpthread(int port) : thread(false), port(port) {}
+ virtual ~ftpthread() { waitfor(); }
+};
+
+void ftpthread::execute()
+{
+
+ bindall(port);
+ while(true)
+ {
+ ipstream * client = new ipstream();
+ s.wait();
+ serve(*client);
+ ftp * f = new ftp(client); // thread will automatically be freed
+ // don't believe me?
+ // I don't either. check pthread.cxx
+ // also Dr. Memory verifies this
+ // I'll believe Dr. Memory over you
+ f->start();
+ }
+}
+
+int main(int argc, char * args[])
+{
+ int port = atoi(args[1]);
+ ftpthread thftp(port);
+ thftp.start();
+
+ thftp.waitfor();
+ return 0;
+}
\ No newline at end of file