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