diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LICENSE Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,34 @@ + + + LICENSE + + + C++ Portable Types Library (PTypes) + + Copyright (C) 2001-2007 Hovik Melikyan + + http://www.melikyan.com/ptypes/ + + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + + + Hovik Melikyan + h@melikyan.com + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,36 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for all Unix platforms, places the library in lib/, +# the shared library in so/. Also builds the test program +# src/ptypes_test and the sample program bin/wshare. +# + +UMAKEFILE=Makefile.`uname` + +all: + cd src ; make -f $(UMAKEFILE) all + cd wshare ; make -f $(UMAKEFILE) all + +clean: + cd src ; make -f $(UMAKEFILE) clean + cd wshare ; make -f $(UMAKEFILE) clean + +clean-src: + cd src ; make -f $(UMAKEFILE) clean-src + cd wshare ; make -f $(UMAKEFILE) clean-src + +install: + cd src ; make -f $(UMAKEFILE) install + +uninstall: + cd src ; make -f $(UMAKEFILE) uninstall + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/async.examples.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/async.examples.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,204 @@ + + + +PTypes: multithreading: examples + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Multithreading: +Examples

+

Example 1. This simple example shows the use of mutex objects to safely +perform calculation that involves more than one global variable. Note that using +the rwlock class instead of mutex +can improve performance by allowing multiple threads call avg_get() +at once.

+
+
int avg_sum = 0;
+int avg_cnt = 0;
+
+mutex avg_lock;
+
+void avg_add(int v)
+{
+    scopelock lock(avg_lock);
+    avg_sum += v;
+    avg_cnt++;
+}
+
+int avg_get()
+{
+    int result;
+    {
+        scopelock lock(avg_lock);
+        if (avg_cnt == 0)
+            result = 0;
+        else
+            result = avg_sum / avg_cnt;
+    }
+    return result;
+}
+
+
+


+Example 2. A multithreaded TCP server that uses the jobqueue +class to maintain a thread pool - a fixed list of reusable threads that receive +job `assignments' from a queue. The code below can be used as a template for a +multithreaded network server.

+
+
#include <ptypes.h>
+
+#include <ptime.h>
+#include <pasync.h>
+#include <pinet.h>
+
+USING_PTYPES
+
+
+const int testport = 8085;
+const int maxthreads = 30;
+const int maxtoken = 4096;
+
+const int MSG_MYJOB = MSG_USER + 1;
+
+
+class myjobthread: public thread
+{
+protected:
+    int id;
+    jobqueue* jq;
+    virtual void execute();
+public:
+    myjobthread(int iid, jobqueue* ijq)
+        : thread(false), id(iid), jq(ijq)  {}
+    ~myjobthread()  { waitfor(); }
+};
+
+
+class myjob: public message
+{
+public:
+    ipstream* client;
+    myjob(ipstream* iclient)
+        : message(MSG_MYJOB), client(iclient)  {}
+    ~myjob()  { delete client; }
+};
+
+
+void myjobthread::execute()
+{
+    bool quit = false;
+    while (!quit)
+    {
+        // get the next message from the queue
+        message* msg = jq->getmessage();
+
+        try
+        {
+            switch (msg->id)
+            {
+            case MSG_MYJOB:
+                {
+                    ipstream* client = ((myjob*)msg)->client;
+
+                    // read the request line
+                    string req = lowercase(client->line(maxtoken));
+                    if (req == "hello")
+                    {
+                        // send our greeting to the client
+                        client->putline("Hello, " + iptostring(client->get_ip()) + ", nice to see you!");
+                        client->flush();
+
+                        // log this request
+                        pout.putf("%t  greeting received from %a, handled by thread %d\n",
+                            now(), long(client->get_ip()), id);
+                    }
+                    client->close();
+                }
+                break;
+
+            case MSG_QUIT:
+                // MSG_QUIT is not used in our example
+                quit = true;
+                break;
+            }
+        }
+        catch(exception*)
+        {
+            // the message object must be freed!
+            delete msg;
+            throw;
+        }
+        delete msg;
+    }
+}
+
+
+void servermain(ipstmserver& svr)
+{
+    jobqueue jq;
+    tobjlist<myjobthread> threads(true);
+
+    // create the thread pool
+    int i;
+    for(i = 0; i < maxthreads; i++)
+    {
+        myjobthread* j = new myjobthread(i + 1, &jq);
+        j->start();
+        threads.add(j);
+    }
+
+    ipstream* client = new ipstream();
+
+    pout.putf("Ready to answer queries on port %d\n", testport);
+
+    while(true)
+    {
+        svr.serve(*client);
+
+        if (client->get_active())
+        {
+            // post the job to the queue; the client object will be freed
+            // automatically by the job object
+            jq.post(new myjob(client));
+            client = new ipstream();
+        }
+    }
+}
+
+
+int main()
+{
+    ipstmserver svr;
+
+    try
+    {
+        // bind to all local addresses on port 8085
+        svr.bindall(testport);
+
+        // enter an infinite loop of serving requests
+        servermain(svr);
+    }
+    catch(estream* e)
+    {
+        perr.putf("FATAL: %s\n", pconst(e->get_message()));
+        delete e;
+    }
+
+    return 0;
+}
+
+
+

See also: thread, mutex, +rwlock, jobqueue, +message, Networking +examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/async.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/async.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,67 @@ + + + +PTypes: multithreading + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Multithreading

+ +

PTypes provides a minimal set of utility objects for creating complex multithreaded +and event-driven applications. In addition to threads +and inter-thread synchronization primitives semaphore, +mutex, rwlock and +trigger the library also allows you to create +message queues (msgqueue) typically used in +windowed or other event-driven environments. The jobqueue +class helps to build multithreaded server and robot applications with a pool of +reusable thread objects.

+

The implementation and interfaces of threads and synchronization objects vary +on platforms supported by the library. If an operating system lacks one of the +features, PTypes implements it using the other primitives present in that OS. +Please, see <pasync.h> for the implementation +cross-reference of the synchronization primitives.

+

These interfaces except the atomic functions are available only in multithreaded +versions of the library.

+

The multithreading classes are declared in <pasync.h>.

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/async.jobqueue.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/async.jobqueue.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,82 @@ + + + +PTypes: multithreading: jobqueue + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Multithreading: +jobqueue

+
+
#include <pasync.h>
+
+class jobqueue {
+    jobqueue(int limit = DEF_QUEUE_LIMIT);
+
+    void post(message* msg);
+    void post(int id, int param = 0);
+    void posturgent(message* msg);
+    void posturgent(int id, int param = 0);
+    message* getmessage(int timeout = -1);
+
+    int get_count();
+    int get_limit();
+}
+
+

The jobqueue class implements a thread-safe list +of objects of type message +or any derivative class. Jobqueue supports posting to +and reading from the list from multiple threads simultaneously.

+

The jobqueue class can help to build multithreaded +server/robot applications by maintaining a pool of reusable threads that receive +job 'assignments' from a queue. This threading model can be faster compared to +applications that create and destroy separate thread objects for each task. See +Examples for a full-featured server template +with a thread pool.

+

jobqueue::jobqueue(int limit = DEF_QUEUE_LIMIT) constructs +a job queue object. Limit specifies the maximum number +of messages this queue can hold. If the limit is reached, the next thread that +posts a message will wait until the queue becomes available again. In this version +the default for limit is 5000.

+

void jobqueue::post(message* msg) adds a message to +the queue. Msg can be an object of class message +or any derivative class. The message object should always +be created dynamically using operator new. The messages +in the queue are processed in order they were posted, i.e. on first-in-first-out +basis.

+

void jobqueue::post(int id, pintptr param = 0) creates +a message object using id and param +and calls post(message*).

+

void msgqueue::posturgent(message* msg) posts a message +object "out of turn", i.e. this message will be processed first. The +messages posted through this method are processed on first-in-last-out basis. +post() and posturgent() can +be used alternately on the same queue.

+

void jobqueue::posturgent(int id, pintptr param = 0) +creates a message object using id and param +and calls posturgent(message*).

+

message* jobqueue::getmessage(int timeout = -1) retrieves +the next message from the queue or waits if there are no messages available. The +timeout parameter specifies the timeout value in milliseconds. +If timeout is -1 (the default) getmessage() +will wait for a message infinitely. This function returns a message object, or +otherwise NULL if the time specified in timeout +has elapsed. NOTE: the message object returned by this function must be +freed with operator delete. It is safe to call getmessage() +concurrently.

+

int jobqueue::get_count() returns the number of messages +currently in the queue.

+

int jobqueue::get_limit() returns the queue limit +set by the constructor.

+

See also: message, msgqueue, +Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/async.message.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/async.message.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,51 @@ + + + +PTypes: multithreading: message + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Multithreading: +message

+
+
#include <pasync.h>
+
+struct message {
+    int id;
+    pintptr param;
+    pintptr result;
+
+    message(int id, pintptr param = 0);
+}
+
+

A message object or an object of a derived class +can be used to post data to message queues (msgqueue) +or job queues (jobqueue). Messages are distinguished +by a ID that are defined in your application. The user message IDs can be in the +range 0 through INT_MAX. Negative +values are reserved for internal use by the library.

+

A simple message can also contain an additional parameter of type pintptr, +which is an integer with a size equal to the size of a pointer on the given platform. +For more complex message structures you can define classes derived from message + - the message queue manager can work with any descendant class as well.

+

message::message(int id, pintptr param = 0) constructs +a message object and assigns id and param +fields. param is an additional field that can be used +in your application at your own discretion.

+

int message::id -- this field contains a message ID +assigned through the constructor.

+

pintptr message::param contains the optional parameter.

+

pintptr message::result -- through this field a message +handler can return some simple answer to the sender of this message.

+

See also: msgqueue, jobqueue, +Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/async.msgqueue.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/async.msgqueue.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,148 @@ + + + +PTypes: multithreading: msgqueue + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Multithreading: +msgqueue

+
+
#include <pasync.h>
+
+class msgqueue {
+    msgqueue(int limit = DEF_QUEUE_LIMIT);
+
+    // functions calling from the owner thread:
+    void processone();
+    void processmsgs();
+    void run();
+
+    // functions calling from any thread:
+    void post(message* msg);
+    void post(int id, pintptr param = 0);
+    void posturgent(message* msg);
+    void posturgent(int id, pintptr param = 0);
+    int  send(message* msg);
+    int  send(int id, pintptr param = 0);
+    int  get_count();
+    int  get_limit();
+
+    // message handlers
+    virtual void msghandler(message& msg) = 0;
+    void defhandler(message& msg);
+}
+
+
+

The msgqueue class implements a queue of message +objects and is typically used to synchronously exchange data in a multithreaded +environment.

+

The thread which created the msgqueue object can +retrieve messages from the queue using one of run(), +processmsgs(), processone(). +Applications always define a class derived from msgqueue +and override the pure virtual method msghandler(). The +overridden method receives message structures and performs +appropriate actions depending on the message ID. Any other thread or even multiple +threads in your application can send or post messages to the given queue using +post(), posturgent() or send().

+

Msgqueue can serve as a synchronization object between +threads. Unlike semaphores, where both sending and receiving threads can "hang" +when waiting for readiness of the peer, msgqueue allows +the sender to send data and immediately continue the execution. The receiver in +its turn processes messages one by one in the same order as they were posted. +

+

Threads can not only exchange data through a message queue, but also send simple +notifications about various events. Message queues can as well be used in single-threaded +applications with event-driven logic.

+

A simple example of using msgqueue could be a server +application with multiple threads, each serving one client; the server maintains +a log file or a table in a database where it records various events. To record +events synchronously the client threads are sending appropriate messages to the +main thread. The client threads never waste time, they just post their messages +and immediately continue their work.

+

IMPORTANT NOTES: (1) a message object should +always be constructed dynamically, i.e. using operator new; +(2) a message object is always destroyed by the queue +manager after it has been processed; (3) a message object +can be sent and processed only once.

+

A slower but more universal alternative to the message queue is local pipe +(see infile::pipe()).

+

msgqueue::msgqueue(int limit = DEF_QUEUE_LIMIT) constructs +a message queue object. It doesn't matter which thread is creating this object, +but later only one thread can process the queue and handle messages. Limit +specifies the maximum number of unhandled messages this queue can hold. If the +limit is reached, the next thread that posts a message will wait until the queue +becomes available again. In this version the default for limit +is 5000.

+

void msgqueue::processone() processes one message +from the queue. This method may "hang" if no messages are available. +processone() calls the overridden msghandler() +and then destroys the message object.

+

void msgqueue::processmsgs() processes all messages +in the queue and returns to the caller. If there are no messages in the queue, +processmsgs() returns immediately. Each message is processed +as described for processone().

+

void msgqueue::run() enters an infinite loop of message +processing which can only be terminated by sending or posting a special message +MSG_QUIT (e.g. post(MSG_QUIT)). +Each message is processed as described for processone().

+

void msgqueue::post(message* msg) adds a message to +the queue. Msg can be an object of class message +or any derivative class. The message object should always +be created dynamically using operator new. The messages +in the queue are processed in order they were posted, i.e. on first-in-first-out +basis. post() can be called from any thread, including +the thread owning the queue.

+

void msgqueue::post(int id, pintptr param = 0) creates +a message object using id and param +and calls post(message*).

+

void msgqueue::posturgent(message* msg) posts a message +object "out of turn", i.e. this message will be processed first. The +messages posted through this method are processed on first-in-last-out basis. +post() and posturgent() can +be used alternately on the same queue. Like post(), +this method can be called from any thread.

+

void msgqueue::posturgent(int id, pintptr param = 0) +creates a message object using id and param +and calls posturgent(message*).

+

pintptr msgqueue::send(message* msg) calls the message +handler directly, by-passing the queue. If the sender is the same as the thread +owning the queue, send() simply calls msghandler(). +Otherwise, if the sender is a concurrent thread, send() +enters an effective wait state until the message is processed by the owner thread. +The return value is the value of result in the message +object. In both cases the message is destroyed upon return from send().

+

pintptr msgqueue::send(int id, pintptr param = 0) +creates a message object using id and param +and calls send(message*). The return value is the value +of result in the message object.

+

int msgqueue::get_count() returns the number of messages +currently in the queue.

+

int msgqueue::get_limit() returns the queue limit +set by the constructor.

+

virtual void msgqueue::msghandler(message& msg) this +pure virtual method should be overridden to provide application-specific message +handling functionality. msghandler() usually checks +the message ID through a switch statement. If the message +ID is unknown to the application, defhandler() should +be called. The message object msg CAN NOT be reused +with post(), posturgent() +or send(), neither it can be destroyed within the message +handler. The message handler can assign some value to msg.result +to return a simple answer to the caller of send().

+

void msgqueue::defhandler(message& msg) is called +from within user-defined msghandler() when the message +ID is unknown to the application. defhandler() processes +some messages internally used by the library, e.g. MSG_QUIT.

+

See also: message, jobqueue

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/async.mutex.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/async.mutex.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,87 @@ + + + +PTypes: multithreading: mutex + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Multithreading: +mutex

+
+
#include <pasync.h>
+
+class mutex {
+    mutex();
+
+    void enter();
+    void leave();
+
+    void lock();      // alias for enter()
+    void unlock();    // alias for leave()
+}
+
+class scopelock {
+    scopelock(mutex&);
+    ~scopelock();
+}
+
+
+

Mutex (mutual exclusion) is another synchronization +object which helps to protect shared data structures from being concurrently accessed +and modified.

+

Accessing and changing simple variables like int +concurrently can be considered safe provided that the variable is aligned on a +boundary "native" to the given CPU (32 bits on most systems). More often, +however, applications use more complex shared data structures which can not be +modified and accessed at the same time. Otherwise, the logical integrity of the +structure might be corrupt from the "reader's" point of view when some +other process sequentially modifies the fields of a shared structure.

+

To logically lock the part of code which modifies such complex structures the +thread creates a mutex object and embraces the critical code with calls to enter() +and leave(). Reading threads should also mark their +transactions with enter() and leave() +for the same mutex object. When either a reader or a writer enters the critical +section, any attempt to enter the same section concurrently causes the thread +to "hang" until the first thread leaves the critical section.

+

If more than two threads are trying to lock the same critical section, mutex +builds a queue for them and allows threads to enter the section only one by one. +The order of entering the section is platform dependent.

+

To avoid infinite locks on a mutex object, applications usually put the critical +section into try {} block and call leave() +from within catch {} in case an exception is raised +during the transaction. The scopelock class provides +a shortcut for this construct: it automatically locks the specified mutex object +in its constructor and unlocks it in the destructor, so that even if an exception +is raised inside the scope of the scopelock object leave() +is guaranteed to be called.

+

More often applications use a smarter mutual exclusion object called read/write +lock -- rwlock.

+

PTypes' mutex object encapsulates either Windows +CRITICAL_SECTION structure or POSIX mutex object and implements the minimal set +of features common to both platforms. Note: mutex may not be reentrant +on POSIX systems, i.e. a recursive lock from one thread may cause deadlock.

+

mutex::mutex() creates a mutex object.

+

void mutex::enter() marks the start of an indivisible +transaction.

+

void mutex::leave() marks the end of an indivisible +transaction.

+

void mutex::lock() is an alias for enter().

+

void mutex::unlock() is an alias for leave().

+

scopelock::scopelock(mutex& m) creates a scopelock +object and calls enter() for the mutex object m.

+

scopelock::~scopelock() calls leave() +for the mutex object specified during construction and destroys the scopelock +object.

+

See also: thread, rwlock, +trigger, semaphore, +Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/async.rwlock.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/async.rwlock.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,82 @@ + + + +PTypes: multithreading: rwlock + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Multithreading: +rwlock

+
+
#include <pasync.h>
+
+class rwlock {
+    rwlock();
+    void rdlock();
+    void wrlock();
+    void unlock();
+}
+
+class scoperead {
+    scoperead(rwlock&);
+    ~scoperead();
+}
+
+class scopewrite {
+    scopewrite(rwlock&);
+    ~scopewrite();
+}
+
+

Rwlock (read/write lock) is a variation of mutex +with a possibility to control critical sections more efficiently. Unlike the simple +mutex, rwlock allows multiple reader threads +to enter the critical section, and only one writer thread at a time. Reading +and writing in this context means access to a resource or compound data shared +between threads. Reader threads must lock the critical section with rdlock() +and the writers must lock it with wrlock(). Both leave +the critical section with unlock().

+

This class incorporates POSIX rwlock interface on UNIX and library's own implementation +on Windows and MacOS X. When using the rwlock class +on Linux, you need to define a symbol _GNU_SOURCE either +in the command line, or anywhere in your source before including any system headers.

+

Analogously to scopelock (see mutex), +scoperead and scopewrite are +fully-inline'd utility classes provided for exception-safe locking of operator +blocks.

+

Please, see Portability and performance issues +for additional notes on rwlock implementation.

+

rwlock::rwlock() creates a rwlock +object.

+

void rwlock::rdlock() locks the object for reading. +Multiple threads can enter the critical section through rdlock(), +however, if the object is already locked for writing, all reader threads wait +until the writer leaves the critical section.

+

void rwlock::wrlock() locks the object for writing. +If there are readers inside the critical section, the writer waits until all threads +leave and unlock the object. Only one writer at a time can enter the critical +section.

+

void rwlock::unlock() unlocks the object. Both readers +and writers must use this method when leaving the critical section.

+

scoperead::scoperead(rwlock& rw) creates a scoperead +object and calls rdlock() for the object rw.

+

scoperead::~scoperead() calls unlock() +for the rwlock object specified during construction +and destroys the scoperead object.

+

scopewrite::scopewrite(rwlock& rw) creates a scopewrite +object and calls wrlock() for the object rw.

+

scopewrite::~scopewrite() calls unlock() +for the rwlock object specified during construction +and destroys the scopewrite object.

+

See also: thread, mutex, +trigger, semaphore, +Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/async.semaphore.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/async.semaphore.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,117 @@ + + + +PTypes: multithreading: semaphore + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Multithreading: +semaphore & timedsem

+
+
#include <pasync.h>
+
+class semaphore {
+    semaphore(int initvalue);
+    void wait();
+    void post();
+    void signal();    // alias for post()
+}
+
+class timedsem {
+    timedsem(int initvalue);
+    bool wait( [ int milliseconds ] );
+    void post();
+    void signal();
+}
+
+
+

Semaphore is a special helper object with very simple logic which is typically +used to synchronize the execution of concurrent threads. A semaphore object can +be considered as an integer value which has one additional feature: if its value +is 0, an attempt to decrement this value will cause the calling thread to "hang" +until some other thread increments it. "Hanging" on the semaphore means +entering effective wait state and consuming no or little CPU time, depending on +the operating system.

+

One example showing the use of semaphores is when one thread needs to send +data (e.g. through a buffer) to another thread. In multithreading environments +there is no guarantee in which order two threads will come to the point where +the first thread is filling the data buffer and the other thread is reading it. +Therefore, these two threads need to synchronize execution at the exchange point. +Semaphore's logic for this case is fairly simple: the reader thread calls wait() +before reading the buffer and "hangs" if the semaphore is not +yet signaled. The writer thread calls post() after filling the buffer with +data and thus signals the reader thread that the data buffer is ready. This schema +ensures that the data buffer will be read by the second thread only when the data +is actually ready.

+

If the data exchange cycle is iterative you will have to make sure also that +the buffer is not filled twice before the reading thread takes the first data +chunk. In this situation another semaphore should be created with reverse logic: +the semaphore is set to signaled state when the reading thread has taken the first +data chunk and is ready to take the second chunk. The writing thread, in its turn, +waits on this semaphore to make sure the buffer is ready for the successive data +chunk.

+

In more complex applications when many threads need to exchange data with each +other or with the main application thread, message queues can be used instead +of semaphores. The message queue object itself is another example of using semaphores +(please see pmsgq.cxx source file).

+

You can use semaphores when your application needs to limit the number of concurrently +running threads of the same type. A typical web robot application, for example, +creates a new thread for each download process. To limit the number of threads +the application creates a semaphore with the initial value equal to the maximum +allowed number of threads. Each new thread decrements the semaphore by calling +wait() and then increments it with post() +upon termination. If the maximum allowed number of threads is reached, the next +thread calling wait() will "hang" until one +of the running threads terminates and calls post().

+

PTypes' semaphore object encapsulates either Windows +semaphore or an implementation based on POSIX synchronization primitives. This +object implements the minimal set of features common to both Windows and POSIX +semaphores. Besides, semaphores can not be shared between processes on some operating +systems, thus limiting the use of PTypes' semaphores to one process.

+

PTypes' timedsem adds timed waiting feature to +the simple semaphore. This class has an interface compatible with the simple semaphore +with one additional function - wait(int) with timer. +The reason this feature is implemented in a separate class is that not all platforms +support timed waiting. Wherever possible, PTypes uses the system's native sync +objects, or otherwise uses its own implementation based on other primitives. Note +that timedsem can be used both for infinitely waiting +and timed waiting; it is, however, recommended to use simple semaphore +if you are not going to use timed waiting.

+

As an example of using timedsem see implementation +of thread 'relaxing' mechanism in include/pasync.h +and src/pthread.cxx.

+

semaphore::semaphore(int initvalue) constructs a +semaphore object with the initial value initvalue.

+

void semaphore::wait() decrements the semaphore's +value by 1. wait() can enter effective wait state if +the value becomes -1, in which case the thread will "hang" until some +other thread increments the value by calling post().

+

void semaphore::post() increments the semaphore's +value by 1. post() can release some other thread waiting +for the same semaphore if its value was -1.

+

void semaphore::signal() is an alias for post().

+

timedsem::timedsem(int initvalue) constructs a +semaphore object with an interface fully compatible with (but not inherited from) +semaphore. This class has one additional method for +timed waiting (see below).

+

bool timedsem::wait( [ int milliseconds ] ) decrements +the semaphore's value by 1 and enters effective wait state if the value becomes +-1. Unlike simple wait() this function will 'wake' and +return if the time specified in milliseconds has elapsed, +in which case the function returns false. If the semaphore was signaled with post() +or signal() before the time elapses this function returns +true. If milliseconds is omitted or is -1 the function +will wait infinitely, like simple wait().

+

See also: thread, mutex, +rwlock, trigger, +msgqueue, Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/async.thread.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/async.thread.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,117 @@ + + + +PTypes: multithreading: thread + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Multithreading: +thread

+
+
#include <pasync.h>
+
+class thread {
+    thread(bool autofree);
+    ~thread();
+
+    void start();
+    void waitfor();
+    void signal();
+    pthread_id_t get_id();
+    bool get_running();
+    bool get_finished();
+    bool get_signaled();
+
+    virtual void execute() = 0;
+    virtual void cleanup() = 0;
+    bool relax(int milliseconds);
+}
+
+

Create a descendant of thread to represent an execution +thread in a multithreaded application. All threads are running within the framework +of the parent process and share the same global variables. Each thread, however, +has its own stack. The execution of a thread can be started either from the main +process or from another thread. Further, the newly launched thread executes its +code concurrently.

+

Multithreading can significantly improve your application when a process consumes +time by waiting for data from some communication device, a slow storage device +or user input. When such pieces of code run concurrently the CPU is loaded more +efficiently. Also, many networking services use threading to serve multiple users +simultaneously.

+

When threads concurrently access and modify shared data structures precautions +should be taken to preserve logical integrity of these data structures. Synchronization +between threads is performed using either of: semaphore, +mutex, rwlock, +trigger or msgqueue.

+

thread::thread(bool autofree) creates a thread object, +but does not run it. If autofree is true +the thread will destroy itself upon termination. Note, that you can use autofree +only for dynamically allocated thread objects. A variable that holds a pointer +to a dynamic autofree thread object can be considered +invalid after a call to start().

+

thread::~thread() destroys the thread object. Usually +both the constructor and the destructor for non-autofree threads are called from +a different context. In contrary, autofree threads call their destructors from +their own context.

+

void thread::start() runs the thread. The overridden +virtual method execute() is called asynchronously. Start() +itself returns immediately. Each thread object can be run only once.

+

void thread::waitfor() waits for the thread to terminate. +This function is called when a thread needs to synchronize its execution with +the completion of the target non-autofree thread. For non-autofree threads this +method must be called at least once and within the scope of a thread that +called start(). For convenience, you can place a call +to waitfor() in the overridden destructor. waitfor(), +however, can not be called for autofree threads.

+

void thread::signal() sets signaled attribute to true +and possibly wakes up the thread if in a `relaxed' state (see relax() +below). signal() is usually called from a different +thread to let the given thread know that the execution should be terminated as +soon as possible. If the given thread performs an iteration one of the conditions +of leaving the loop should be (!get_signaled()). Signal() +can be called only once for a thread object.

+

pthread_id_t thread::get_id() returns the thread +ID assigned by the operating system. This ID can then be used in call to pthrequal().

+

bool thread::get_running() returns true +if the given thread object is running. This property is never set to false +once the thread started. To check whether the thread finished its job, i.e. returned +from execute(), use get_finished().

+

bool thread::get_finished() returns true +if thread has already terminated its execution, or, in other words, has left execute().

+

bool thread::get_signaled() returns true +if the thread object is in signaled state, i.e. signal() +has been called from a concurrent thread. See also signal().

+

virtual void thread::execute() -- this pure virtual +method should be overridden in the descendant class to implement the functionality +of your thread. execute() can be viewed as main() +for your mini-process. Typically, you create a class descendant from thread +and override at least two virtual methods: execute() +and cleanup().

+

virtual void thread::cleanup() -- this pure virtual +method should be overridden in the descendant class. cleanup() +is called either when the thread terminates normally or when an exception is raised +within the thread's context. When implementing this method you might want to clean +up any memory and other resources allocated by your thread object. cleanup() +is guaranteed to be called once upon termination of the thread. To properly shut +down the thread, avoid using operations that can cause exceptions in cleanup().

+

bool thread::relax(int milliseconds) is a protected +member function which can be called only from within the overridden execute() +method. This function suspends the execution of the thread until either of: the +specified amount of time is elapsed, in which case the function returns false, +or signal() is called from a concurrent thread, in which +case relax() returns true. If parameter milliseconds +is -1 the function will wait infinitely. The relax/signal mechanism is useful +for threads doing some job that requires taking periodic actions in the background.

+

See also: semaphore, mutex, +rwlock, trigger, +Utilities, Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/async.trigger.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/async.trigger.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,60 @@ + + + +PTypes: multithreading: trigger + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Multithreading: +trigger

+
+
#include <pasync.h>
+
+class trigger {
+    trigger(bool autoreset, bool initstate);
+    void wait();
+    void post();
+    void signal();      // alias for post()
+    void reset();
+}
+
+
+

Trigger is a simple synchronization object typically +used to notify one or more threads about some event. Trigger +can be viewed as a simplified semaphore, which has only two states and does not +count the number of wait's and post's. Multiple threads can wait for an event +to occur; either one thread or all threads waiting on a trigger can be released +as soon as some other thread signals the trigger object. +Auto-reset triggers release only one thread each time post() +is called, and manual-reset triggers release all waiting threads at once. Trigger +mimics the Win32 Event object.

+

trigger::trigger(bool autoreset, bool initstate) creates +a trigger object with the initial state initstate. The +autoreset feature defines whether the trigger object +will automatically reset its state back to non-signaled when post() +is called.

+

void trigger::wait() waits until the state of the +trigger object becomes signaled, or returns immediately if the object is in signaled +state already.

+

void trigger::post() signals the trigger object. If +this is an auto-reset trigger, only one thread will be released and the state +of the object will be set to non-signaled. If this is a manual-reset trigger, +the state of the object is set to signaled and all threads waiting on the object +are being released. Subsequent calls to wait() from +any number of concurrent threads will return immediately.

+

void trigger::signal() is an alias for post().

+

void trigger::reset() resets the state of the trigger +object to non-signaled.

+

See also: thread, mutex, +rwlock, semaphore, +Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/async.utils.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/async.utils.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,68 @@ + + + +PTypes: multithreading: utils + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Multithreading: +Atomic functions, utilities

+
+
#include <pasync.h>
+
+int pexchange(int* target, int value);
+void* pexchange(void** target, void* value);
+int pincrement(int* target);
+int pdecrement(int* target);
+
+template <class T> T* tpexchange(T** target, T* value);
+
+void psleep(unsigned milliseconds);
+pthread_id_t pthrself();
+bool pthrequal(pthread_id_t id);
+
+
+

The atomic functions pexchange(), pincrement() +and pdecrement() can be used in place of mutex locking +in some simple situations. A typical usage of pexchange() +in a multithreaded environment could be, for example, freeing a dynamic object +and assigning NULL to the pointer atomically to prevent concurrent threads +from freeing the same object more than once.

+

It is sometimes necessary to increment or decrement some shared counter and +atomically compare it with some value. For example, you have a shared resource +and you keep track of its usage by maintaining a reference counter. When this +counter reaches 0 you want to free the shared resource. To avoid conflicts between +concurrent threads you need to decrement the counter and atomically compare it +with 0. In this situation you can use pdecrement() instead +of time-consuming mutex locking. (For additional notes, see Portability +and performance issues.)

+

int pexchange(int* target, int value) -- atomically +exchanges two int values.

+

void* pexchange(void** target, void* value) -- atomically +exchanges two pointers.

+

int pincrement(int* target) -- atomically increments +the value of *target and returns the new value.

+

int pdecrement(int* target) -- atomically decrements +the value of *target and returns the new value.

+

template <class T> T* tpexchange(T** target, T* value) +-- is equivalent to pexchange() that adds compile-time +type checking. Use this template to check the correspondence of pointer types +of target and the returning value.

+

void psleep(unsigned milliseconds) -- suspends execution +for the specified amount of time in milliseconds.

+

pthread_id_t pthrself() -- returns the thread ID of +the calling thread.

+

bool pthrequal(pthread_id_t id) -- checks whether +the calling thread has the given thread id.

+

See also: semaphore, mutex, +thread

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/basic.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/basic.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,41 @@ + + + +PTypes: basic types + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types

+ + +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/changes.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/changes.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,453 @@ + + + +PTypes: Changes + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Introduction: +Changes

+


+Version 2.1.1

+ +

Version 2.1.0

+ +

Version 2.0.3

+ +

Version 2.0.2

+ +

Version 2.0.1

+ +

Version 2.0.0

+ +

Version 1.9.0

+ +

Version 1.8.3

+ +

Version 1.8.2

+ +

Version 1.8.1

+ +

Version 1.8.0

+ +

Version 1.7.6

+ +

Version 1.7.5

+ +

Version 1.7.4

+ +

Version 1.7.3

+ +

Version 1.7.2

+ +

Version 1.7.1

+ +

Version 1.7.0

+ +

Version 1.6.1

+ +

Version 1.6.0

+ +

Version 1.5.3

+ +

Version 1.5.2

+ +

Version 1.5.1

+ +

Version 1.5.0

+ +

Version 1.4.1

+ +

Version 1.4.0

+ +

Version 1.3.2

+ +

Version 1.3.1

+ +

Version 1.3

+ +

Version 1.2

+ +

Version 1.1 was the first public release

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/compiling.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/compiling.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,130 @@ + + + +PTypes: Compiling and Porting + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Introduction: +Compiling and Porting

+


+Supported platforms and compilers

+
+

Linux/i386, Alpha, PPC, Sparc, AMD64: GNU C/C++

+

MacOS X/Intel, PPC: CC - Apple Objective-C compiler

+

SunOS/Sparc, i386: GNU C/C++

+

FreeBSD: GNU C/C++

+

HP-UX: aCC

+

Windows: MS Visual Studio 7, 8

+


+

+The build process on all platforms produces 3 versions of the library: static +single-threaded, static multithreaded and dynamic (shared) multithreaded. In addition, +MSVC can build debug versions for each of these 3 libraries.

+

Single-threaded versions have a suffix 'n' (non-reentrant) in their names: +libptypesn.a for UNIX and MinGW and ptypesn.lib +for MSVC. They are somewhat faster and smaller than the multithreaded versions +and are intended to be used in smaller projects that do not require to be linked +with the slower reentrant system libraries.

+

The dynamic versions of the library have the library version number in their +names: ptypes21.dll, libptypes.so.21 +and libptypes.21.dylib. The version number in file names +reflects incompatible changes and/or significant enhancement of functionality. +Change in the third number in the version usually indicates a compatible improvement +and/or bug fix release, so it is not reflected in the DLL/so file name.

+
+


+Building on UNIX and MacOS X

+
+

In order to build the library on one of the UNIX systems listed above, run +make in the library's root directory. The makefile in +this directory actually calls makefiles in src/ and +wshare/ with a suffix which is an output of uname +on the given system (e.g. src/Makefile.Linux or src/Makefile.FreeBSD). +Make builds the library and the demo program, and then places:

+ +

The public headers are in include/.

+

When building your own multithreaded application on Linux or FreeBSD, +GCC requires you to specify a special command-line option -pthread +which automatically links POSIX threads library and the reentrant version of libc. +On Linux you should specify a macro -D_GNU_SOURCE +in the command line to include the rwlock interface.

+

When building your multithreaded application on SunOS, you should specify +a macro -D_REENTRANT and also link the following libraries: +-lpthread -lposix4 for multithreaded applications, and +in addition, -lsocket -lnsl for network applications. +NOTE: if you omit -lpthread, the program links +without errors, but then the thread objects fail to initialize.

+
+


+Building on Windows with MSVC 7 or 8

+
+

The MSVC project files are:

+ +

A "solution" file PTypes.sln is provided for building +all components and versions of the library.

+

You can include one of the project files in your own solutions. Make your +project dependent of PTypes to automatically link the library to your program. +To use PTypes headers you will have to explicitly specify the directory in your +project settings, e.g. "..\ptypes\include".

+

In order to link a program against the DLL version of PTypes (ptypes21.dll) +use PTYPES_DLL macro definition when compiling your +modules. You may want to add a post-build command in the MSVC environment that +copies the PTypes DLL to the directory where you build and debug your application.

+

You should link your application with the multithreaded version of CRTL, except +when using the single-threaded ptypesn.lib. When compiling +with the dynamic version of PTypes, it is recommended also to use the multithreaded +DLL version of CRTL.

+

Specify an additional library ws2_32.lib if you are +using PTypes' IP socket classes.

+
+


+PTypes namespace

+
+

The entire PTypes interface is enclosed within a namespace called pt. +The header file <pport.h> provides a +macro USING_PTYPES, which is equivalent to using +namespace pt. This macro allows you to use PTypes interface symbols without +the scope specifier pt:: in your source code.

+
+


+Porting the library to other platforms

+
+

The author would greatly appreciate any effort to port the library to other +popular platforms. If you either ported the library or just found that PTypes +builds with no problem under your favorite platform with your favorite compiler, +then all you'd have to do is to create a makefile with proper definitions in it. +Take a look at Makefile.FreeBSD or Makefile.SunOS, +for example. Besides OS_CXXOPTS you can specify additional +libraries through OS_LDLIBS. Name your makefile so that +running make Makefile.`uname` would work on the given +operating system. Try to build the library and then run src/ptypes_test +to make sure the library is functioning properly.

+

And finally, if you send the changes to the author, then (obviously) others +would be able to benefit from using PTypes on your favorite operating system with +your favorite compiler.

+
+

See also: Deploying the shared (dynamic) +library

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/criterrors.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/criterrors.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,41 @@ + + + +PTypes: critical errors + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Exceptions and critical errors

+

Some of the components in PTypes may produce unrecoverable error conditions, +such like a list index is out of bounds, a stream object is constructed with inconsistent +parameters, an operation on a stream is requested which requires buffering, etc. +These errors are mainly caused by wrong usage of objects or functions of the library.

+

Whenever an unrecoverable error condition is raised, PTypes calls fatal() +with a message describing the error condition and terminates the program. On most +platforms this message is sent to stderr, and +on Windows the message is shown in a simple message box.

+

The function fatal() is declared in <pport.h>.

+

Some library components also raise recoverable error conditions (exceptions). +PTypes only generates exception of type (exception*) +defined in <ptypes.h>, or, in some cases, +a derivative class, e.g. (estream*). An exception object +at least contains an error message which can be retrieved through get_message() +method.

+

NOTE: Exception objects in PTypes are allocated dynamically and therefore, +they should be freed by the catch block if it does not pass the exception farther. +The exception class is derived from unknown to help +you to detect memory leaks in your program. If a thread in a multithreaded application +is created using PTypes thread class, then all PTypes +exceptions thrown in each thread are caught and freed automatically (unless +caught in the user code).

+

See also streams Error handling and Examples.

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/cset.constructors.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/cset.constructors.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,55 @@ + + + +PTypes: cset: constructors + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +cset: Constructors

+
+
#include <ptypes.h>
+
+class cset {
+    cset();
+    cset(const cset& s);
+    cset(const char* setinit);
+}
+
+
+

cset::cset() -- default constructor, initializes +the set object to an empty set.

+

cset::cset(const cset& s) -- copy constructor.

+

cset::cset(const char* setinit) constructs a character +set from a string. The setinit parameter is a sequence +of characters, range specifiers and escape sequences. Range specifier consists +of: lower boundary, dash "-" and higher boundary, e.g. "A-Z". +Escape sequence begins with tilde "~" and can be followed by a two-digit +hexadecimal number. Escape sequences are also used to include special characters +tilde "~" and dash "-" (see examples below).

+

Constructing character sets using this interpreter can be a time-consuming +operation. A better practice is to declare all constant character sets as static +variables, so that the interpretation of all set constructing strings will be +done only once during program startup.

+

An initializer string can also be passed to a cset +object through assign().

+

Note: this constructor does not generate errors if the syntax is violated.

+

Examples:

+
+
cset s1 = "135A-CZ";            // digits 1, 3, 5, letters A through C, and also Z
+cset wspace1 = "~09~0d~0a ";    // tab, CR, LF and space
+cset wspace2 = "~00-~20";       // all control and whitespace chars
+cset s2 = ":@~~";               // colon, at and tilde (must be escaped with another tilde)
+
+
+

See also: Operators, Manipulation

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/cset.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/cset.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,60 @@ + + + +PTypes: cset + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +cset

+ +

The character set class (cset) implements Pascal-style +set of integer values from 0 to 255, or set of characters. Unlike Pascal sets, +the range of a cset cannot be changed and is always +0 through 255. Cset class implements various operators +(membership, union, intersection, equality, less than or equal to, etc.) as they +are described in the Pascal language. See Operators +for details.

+

Cset is a packed array of 256 bits, it occupies 32 +bytes of static or local memory. Each bit indicates whether the corresponding +character is a member of a given set.

+

Another difference between cset and Pascal sets is +that since C++ compiler does not have a built-in set constructor like the one +in Pascal (e.g. ['A'..'Z', 'a'..'z']), cset provides +a simple run-time interpreter instead (see Constructors).

+

The cset class is declared in <ptypes.h>.

+

The example below shows the general usage of character sets.

+
+
cset s = "A-Za-z!";       // same as ['A'..'Z', 'a'..'z', '!'] in Pascal
+
+include(s, '_');          // include underscore character
+include(s, '0', '9');     // include all chars from '0' to '9'
+
+if ('a' & s)              // check membership
+    cout << "Letter 'a' found in the set! :)\n";
+
+const cset letters = "A-Za-z_";     // define a set of letters
+string tok = pin.token(letters);    // read a token from the input stream
+
+

See also: Constructors, +Operators, Manipulation

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/cset.manipulation.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/cset.manipulation.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,51 @@ + + + +PTypes: cset: manipulation + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +cset: Manipulation

+
+
#include <ptypes.h>
+
+void   assign(cset& s, const char* setinit);
+string asstring(const cset& s);
+void   clear(cset& s);
+void   fill(cset& s);
+void   include(cset& s, char b);
+void   include(cset& s, char min, char max);
+void   exclude(cset& s, char b);
+
+
+

assign(cset& s, const char* setinit) works the same +way as cset(const char*) constructor (see constructors).

+

string asstring(const cset& s) returns a string +representing the given set s using cset(const +char*) syntax. Typically used for debugging.

+

clear(cset& s) assigns an empty set (removes all +members) to the set s.

+

fill(cset& s) assigns all 1s to the set - all elements +become members of this set.

+

include(cset& s, char b) adds the element b +to the set s. Equivalent to s += +b.

+

include(cset& s, char min, char max) adds a range +of elements min through max +to the set s.

+

exclude(cset& s, char b) removes the element b +from the set s. Equivalent to s -= +b.

+

See also: Constructors, +Operators

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/cset.operators.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/cset.operators.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,89 @@ + + + +PTypes: cset: operators + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +cset: Operators

+
+
#include <ptypes.h>
+
+class cset {
+    // assignment
+    cset& operator =(const cset& s);
+
+    // union
+    cset& operator +=(const cset& s);
+    cset& operator +=(char b);
+    cset  operator +(const cset& s) const;
+    cset  operator +(char b) const;
+    friend cset operator +(char b, const cset& s);
+
+    // difference
+    cset& operator -=(const cset& s);
+    cset& operator -=(char b);
+    cset  operator -(const cset& s) const;
+    cset  operator -(char b) const;
+
+    // intersection
+    cset& operator *=(const cset& s);
+    cset  operator *(const cset& s) const;
+
+    // comparison
+    bool operator ==(const cset& s) const;
+    bool operator !=(const cset& s) const;
+    bool operator <=(const cset& s) const;
+    bool operator >=(const cset& s) const;
+
+    // membership
+    friend bool operator& (char b, const cset& s);
+}
+
+
+

The following rules apply to +, -, and *:

+ +

The following rules apply to comparison operations <=, >=, ==, !=:

+ +

For an ordinal O and a set S, O & S is true just in case O is a member +of S. Unlike the Pascal language, where membership operator is in, PTypes +uses ampersand "&" as a membership test operator.

+

Note: regardless of whether default char is signed or unsigned (usually +set through compiler options) cset always treats char +arguments as unsigned. This means, if the value of an argument is -1, e.g. in +call to operator & or operator ++, the value will be converted to 255, -2 will be treated as 254, etc.

+

See also: Constructors, +Manipulation

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/deploying.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/deploying.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,184 @@ + + + +PTypes: deploying + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Deploying the shared (dynamic) +library

+


+Static vs. dynamic linking

+

PTypes builds two separate versions of the library: static and shared (DLL +on Windows), giving you a choice, and at the same time putting into a dilemma.

+

Both static and dynamic linking have their advantages and disadvantages. While +small applications consisting of a single executable would prefer to link the +library directly, more complex projects with multiple dynamic components and executables +would greatly benefit from going 'totally dynamic', including generic low-level +libraries, such like CRTL and PTypes. Before making a decision, consider the following:

+

Advantages of static linking in general:

+ +

Advantages of dynamic linking in general:

+ +

In summary, dynamic linking is good (1) for big projects, (2) if the library +is widely used by many software vendors in its dynamic (shared) form or (3) to +take advantage of run-time binding.

+


+Using and deploying UNIX shared object

+

PTypes builds a shared object named libptypes.so.20 +(libptypes.20.dylib on MacOS X), creates a 'default' +symbolic link to this library and finally places them both in so/.

+

If you decided to link your program against PTypes shared object instead of +the static library, then all you'd have to do is to change the library path in +your makefile from -L../ptypes/lib to -L../ptypes/so. +When running the program, it will require the shared library to be either in one +of the default locations (usually /usr/lib and /usr/local/lib), +or you will have to override the LD_LIBRARY_PATH environment variable and point +to the directory where the shared object resides, e.g. ~/ptypes/so.

+

The shared object libptypes.so.20 should be deployed +and installed along with your application. The version number '20' will change +when PTypes adds a number of new features and becomes bigger and/or if incompatible +changes take place which make it impossible for older programs to use the new +shared object.

+


+Using and deploying Windows DLL

+

The PTypes MSVC project is configured so that the 'release' version of ptypes20.dll +along with its import library is copied into so\ as +the final step of the build process. This module does not contain any debugging +information and is ready to be deployed. Note that the library itself is linked +against the multithreaded DLL version of CRTL.

+

PTypes places a VERSION resource in the DLL, allowing the system or the setup +program to automatically compare the existing ptypes20.dll +the user may have in the system with the one that comes with your program. This +is usually done from within the installation script.

+

The DLL version of the library built with Dev-C++/MinGW is called ptypes20g.dll. +The reason this name is different is that each C++ compiler uses its own `name +mangling' scheme for exported symbols, so that applications built by one compiler +can't use dynamic libraries built by another one.

+


+Version checking sample code

+

If, for some reason, you wish to check the version of the shared library you +linked with dynamically, you may check the global variable __ptypes_version, +which is declared in <pport.h>. +This variable holds the version number encoded as a single integer, e.g. 0x010902 +designates version 1.9.2. In this form the version numbers (required and actual) +can be easily compared as integers.

+

Note, the name of the library itself reflects major and minor version numbers, +so that only the third component of the version number can vary in the file.

+

If you need to check the version of PTypes before loading the library (for +example, during the installation on UNIX), you may write a program that loads +the shared object and reads the global symbol __ptypes_version +at run-time, using the system dynamic loading interface. Note that this program +itself is not using PTypes. Some UNIX systems require to link the program with +-ldl.

+
+
+
+#ifdef WIN32
+#  include <windows.h>
+#else
# include <dlfcn.h>
#endif + +#include <stdio.h> + + +const unsigned long required = 0x020001; +
+int main() +{ + void* handle; + unsigned long* pversion; + int exitcode = 0; + +#ifdef WIN32 + const char* libname = "ptypes20.dll"; + handle = LoadLibrary(libname); + if (handle == 0) + { + printf("ptypes20.DLL not found\n"); + return 3; + } + pversion = (unsigned long*)GetProcAddress(HMODULE(handle), "__ptypes_version"); +#else + const char* libname = "libptypes.so.20"; + handle = dlopen(libname, RTLD_LAZY); + if (handle == 0) + { + printf("%s\n", dlerror()); + return 3; + } + pversion = (unsigned long*)dlsym(handle, "__ptypes_version"); +#endif + + if (pversion == NULL) + { + printf("Couldn't determine the version number of %s\n", libname); + exitcode = 1; + } + else + { + printf("Found %s, version: %ld.%ld.%ld\n", libname, + (*pversion) >> 16, ((*pversion) >> 8) & 0xff, (*pversion) & 0xff); + if (*pversion < required) + { + printf("Need version %ld.%ld.%ld or later\n", + required >> 16, (required >> 8) & 0xff, required & 0xff); + exitcode = 2; + } + } + +#ifdef WIN32 + FreeLibrary(HMODULE(handle)); +#else + dlclose(handle); +#endif + + return exitcode; +} + +
+
+

See also: Compiling and Porting

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/freshmeat-logo.png Binary file doc/freshmeat-logo.png has changed diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/htsrc.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/htsrc.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,48 @@ + + + +PTypes: header files + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Header files

+ +


+NOTE: for better readability, these listings differ from the originals +in that Windows-specific macros ptpublic and ptdecl +are not shown.

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/include/pasync.h.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/include/pasync.h.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,630 @@ + + + + + + +pasync.h + + +

Index


+ +
+
+
+
+#ifndef __PASYNC_H__ 
+#define __PASYNC_H__ 
+
+#ifdef WIN32 
+#  define _WINSOCKAPI_   // prevent inclusion of winsock.h, since we need winsock2.h 
+#  include <windows.h> 
+#else 
+#  include <pthread.h> 
+#  ifndef __bsdi__ 
+#    include <semaphore.h> 
+#  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 
+
+
+void psleep(uint milliseconds);
+bool pthrequal(pthread_id_t id);  // note: this is NOT the thread handle, use thread::get_id()
+pthread_id_t pthrself();          // ... same
+
+
+// -------------------------------------------------------------------- //
+// --- mutex ---------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+#ifdef WIN32 
+
+struct 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 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 
+
+
+extern pmemlock _mtxtable[_MUTEX_HASH_SIZE];
+
+#define pgetmemlock(addr) (_mtxtable + pintptr(addr) % _MUTEX_HASH_SIZE) 
+
+
+// -------------------------------------------------------------------- //
+// --- trigger -------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+#ifdef WIN32 
+
+class 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 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 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 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 semaphore: public unknown
+{
+protected:
+    sem_t handle;
+public:
+    semaphore(int initvalue);
+    virtual ~semaphore();
+
+    void wait();
+    void post();
+    void signal()  { post(); }
+};
+
+#endif 
+
+
+class 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 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 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 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 T> 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 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 -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/include/pinet.h.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/include/pinet.h.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,494 @@ + + + + + + +pinet.h + + +

Index


+ +
+
+
+
+#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 <winsock2.h> 
+#else 
+#  include <netdb.h>       // for socklen_t 
+#  include <sys/types.h> 
+#  include <sys/socket.h> 
+#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 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; }
+};
+
+
+extern ipaddress ipnone;
+extern ipaddress ipany;
+extern ipaddress ipbcast;
+
+
+//
+// IP peer info: host name, IP and the port name
+// used internally in ipstream and ipmessage
+//
+
+
+class 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
+
+    friend bool 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;
+};
+
+
+string    iptostring(ipaddress ip);
+ipaddress phostbyname(const char* name);
+string    phostbyaddr(ipaddress ip);
+string    phostcname(const char* name);
+
+// internal utilities
+int usockerrno();
+const char* usockerrmsg(int code);
+bool psockwait(int handle, int timeout);
+bool 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 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 ipsvbase: public unknown
+{
+protected:
+    int     socktype;
+    bool    active;
+    tobjlist<ipbindinfo> 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 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 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 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 -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/include/pport.h.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/include/pport.h.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,300 @@ + + + + + + +pport.h + + +

Index


+ +
+
+
+
+#ifndef __PPORT_H__ 
+#define __PPORT_H__ 
+
+
+#if defined(linux) 
+#  include <stdint.h>     // for uintptr_t 
+#endif 
+
+#include <sys/types.h> 
+
+
+#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 
+#  endif 
+#  define ptdecl	__stdcall 
+#  define __PFASTCALL __fastcall 
+#else 
+#  define ptpublic	 
+#  define ptdecl	 
+#  define __PFASTCALL 
+#endif 
+
+
+//
+// versioning
+//
+
+
+extern "C" 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 (*_pcrithandler)(int code, const char* msg);
+
+_pcrithandler getcrithandler();
+_pcrithandler setcrithandler(_pcrithandler newh);
+
+void fatal(int code, const char* msg);
+
+
+//
+// memory management (undocumented)
+// hides some BSD* incompatibility issues
+//
+
+void* memalloc(uint a);
+void* memrealloc(void* p, uint a);
+void  memfree(void* p);
+void  memerror();
+int   memquantize(int);
+
+
+PTYPES_END
+
+
+#endif // __PPORT_H__ 
+
+
+
+
+ +
+ + +
+ diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/include/pstreams.h.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/include/pstreams.h.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,901 @@ + + + + + + +pstreams.h + + +

Index


+ +
+
+
+
+#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 <stdarg.h> 
+#include <errno.h> 
+
+
+#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 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 (*iostatusevent)(iobase* sender, int code);
+
+int unixerrno();
+const char* 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 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;
+
+
+extern int defbufsize;
+extern int stmbalance;
+
+
+//
+// instm - abstract input stream
+//
+
+const char eofchar = 0;
+
+class 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 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
+extern char* shorttimefmt;  // "%d-%b-%Y %X"
+extern char* longtimefmt;   // "%a %b %d %X %Y"
+
+
+//
+// internal class used in fdxstm
+//
+
+class fdxstm;
+
+
+class 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 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 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 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 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 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 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 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 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 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 '\\<server>\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 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 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 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 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 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 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<instm> uin;
+    compref<outstm> 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
+//
+
+extern infile  pin;
+extern logfile pout;
+extern logfile perr;
+extern outnull pnull;
+
+
+#ifdef _MSC_VER 
+#pragma pack(pop) 
+#endif 
+
+
+PTYPES_END
+
+#endif // __PSTREAMS_H__ 
+
+
+
+
+
+ +
+ + +
+ diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/include/ptime.h.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/include/ptime.h.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,166 @@ + + + + + + +ptime.h + + +

Index


+ +
+
+
+
+#ifndef __PTIME_H__ 
+#define __PTIME_H__ 
+
+#ifndef __PPORT_H__ 
+#include "pport.h" 
+#endif 
+
+#ifndef __PTYPES_H__ 
+#include "ptypes.h" 
+#endif 
+
+
+#include <time.h> 
+
+
+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); }
+
+datetime mkdt(int days, int msecs);
+bool     isvalid(datetime);
+datetime now(bool utc = true);
+void     tzupdate();
+int      tzoffset();
+string   dttostring(datetime, const char* fmt);
+string   nowstring(const char* fmt, bool utc = true);
+datetime utodatetime(time_t u);
+struct tm* dttotm(datetime dt, struct tm& t);
+
+// date/calendar manipulation
+bool     isleapyear(int year);
+int      daysinmonth(int year, int month);
+int      daysinyear(int year, int month);
+int      dayofweek(datetime);
+bool     isdatevalid(int year, int month, int day);
+datetime encodedate(int year, int month, int day);
+bool     decodedate(datetime, int& year, int& month, int& day);
+
+// time manipulation
+bool     istimevalid(int hour, int min, int sec, int msec = 0);
+datetime encodetime(int hour, int min, int sec, int msec = 0);
+bool     decodetime(datetime, int& hour, int& min, int& sec, int& msec);
+bool     decodetime(datetime, int& hour, int& min, int& sec);
+
+
+PTYPES_END
+
+#endif // __PTIME_H__ 
+
+
+
+
+ +
+ + +
+ diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/include/ptypes.h.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/include/ptypes.h.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,1248 @@ + + + + + + +ptypes.h + + +

Index


+ +
+
+
+
+#ifndef __PTYPES_H__ 
+#define __PTYPES_H__ 
+
+
+#ifndef __PPORT_H__ 
+#include "pport.h" 
+#endif 
+
+#include <string.h> 
+
+
+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 
+
+
+int   __PFASTCALL pincrement(int* target);
+int   __PFASTCALL pdecrement(int* target);
+int   __PFASTCALL pexchange(int* target, int value);
+void* __PFASTCALL pexchange(void** target, void* value);
+
+template <class T> 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)) 
+
+
+extern char* emptystr;
+
+class variant;
+
+
+class 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);
+    friend char*  setlength(string&, int);
+    friend char*  unique(string&);
+    friend void   concat(string& s, const char* sc, int catlen);
+    friend void   concat(string& s, const char* s1);
+    friend void   concat(string& s, char s1);
+    friend void   concat(string& s, const string& s1);
+    friend string copy(const string& s, int from, int cnt);
+    friend string copy(const string& s, int from);
+    friend void   ins(const char* s1, int s1len, string& s, int at);
+    friend void   ins(const char* s1, string& s, int at);
+    friend void   ins(char s1, string& s, int at);
+    friend void   ins(const string& s1, string& s, int at);
+    friend void   del(string& s, int at, int cnt);
+    friend void   del(string& s, int at);
+    friend int    pos(const char* s1, const string& s);
+    friend int    pos(char s1, const string& s);
+    friend int    pos(const string& s1, const string& s);
+    friend int    rpos(char s1, const string& s);
+    friend bool   contains(const char* s1, int len, const string& s, int at);
+    friend bool   contains(const char* s1, const string& s, int at);
+    friend bool   contains(char s1, const string& s, int at);
+    friend bool   contains(const string& s1, const string& s, int at);
+    friend string 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;
+
+    friend string operator+ (const char* sc, const string& s);
+    friend string 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(); }
+
+
+extern int stralloc;
+
+extern string nullstring;
+
+
+// -------------------------------------------------------------------- //
+// --- string utilities ----------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+string fill(int width, char pad);
+string pad(const string& s, int width, char c, bool left = true);
+
+string itostring(large value, int base, int width = 0, char pad = 0);
+string itostring(ularge value, int base, int width = 0, char pad = 0);
+string itostring(int value, int base, int width = 0, char pad = 0);
+string itostring(unsigned value, int base, int width = 0, char pad = 0);
+string itostring(large v);
+string itostring(ularge v);
+string itostring(int v);
+string itostring(unsigned v);
+
+large  stringtoi(const char*);
+large  stringtoie(const char*);
+ularge stringtoue(const char*, int base);
+
+string lowercase(const char* s);
+string 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 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);
+
+    friend string 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.
+
+extern int objalloc;
+
+class 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 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 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 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
+
+    static void idxerror();
+
+    _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 X, bool initzero = false> class 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<X, initzero>& operator =(const tpodlist<X, initzero>& t)
+                                            { _podlist::operator =(t); return *this; }
+
+    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<X, initzero>& 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<X, initzero>& 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 _objlist: public unknown, protected tpodlist<void*, true>
+{
+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<void*,true>::set_capacity(newcap); }
+    void  clear()                           { set_count(0); }
+    void  pack()                            { tpodlist<void*,true>::pack(); }
+    void  ins(int index, void* obj)         { tpodlist<void*,true>::ins(index, obj); }
+    void  add(void* obj)                    { tpodlist<void*,true>::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 X> 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 <class X> void tobjlist<X>::dofree(void* item)
+{
+    delete (X*)item;
+}
+
+
+template <class X> tobjlist<X>::~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 _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 X> 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 <class X> void tstrlist<X>::dofreeobj(void* obj)
+{
+    delete (X*)obj;
+}
+
+
+template <class X> tstrlist<X>::~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 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 component: public unknown 
+{
+protected:
+    int                  refcount;     // reference counting, used by addref() and release()
+    tobjlist<component>* 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);
+    
+    friend component* addref(component*);
+    friend bool 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 <class T> inline T* taddref(T* c)
+    { return (T*)addref((component*)c); }
+
+
+template <class T> class compref
+{
+protected:
+    T* ref;
+public:
+    compref()                                   { ref = 0; }
+    compref(const compref<T>& r)                { ref = taddref<T>(r.ref); }
+    compref(T* c)                               { ref = taddref<T>(c); }
+    ~compref()                                  { release(ref); }
+    compref<T>& operator =(T* c);
+    compref<T>& operator =(const compref<T>& r) { return operator =(r.ref); }
+    T&   operator *() const                     { return *ref; }
+    T*   operator ->() const                    { return ref; }
+    bool operator ==(const compref<T>& r) const { return ref == r.ref; }
+    bool operator ==(T* c) const                { return ref == c; }
+    bool operator !=(const compref<T>& r) const { return ref != r.ref; }
+    bool operator !=(T* c) const                { return ref != c; }
+         operator T*() const                    { return ref; }
+};
+
+
+template <class T> compref<T>& compref<T>::operator =(T* c)
+{
+    release(tpexchange<T>(&ref, taddref<T>(c)));
+    return *this;
+}
+
+
+// -------------------------------------------------------------------- //
+// --- variant -------------------------------------------------------- //
+// -------------------------------------------------------------------- //
+
+
+enum {
+    VAR_NULL,
+    VAR_INT,
+    VAR_BOOL,
+    VAR_FLOAT,
+    VAR_STRING,
+    VAR_ARRAY,
+    VAR_OBJECT,
+
+    VAR_COMPOUND = VAR_STRING
+};
+
+
+class _varray;
+
+
+class 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
+    friend void 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
+    friend void aclear(variant&);
+    friend variant aclone(const variant&);
+    friend const variant& get(const variant&, const string& key);
+    friend const variant& get(const variant&, large key);
+    friend void put(variant&, const string& key, const variant& item);
+    friend void put(variant&, large key, const variant& item);
+    friend void del(variant&, const string& key);
+    friend void del(variant&, large key);
+
+    // indexed access to arrays
+    friend int  alength(const variant&);
+    friend void apack(variant&);
+    friend bool anext(const variant& a, int&, variant& item);
+    friend bool anext(const variant& a, int&, variant& item, string& key);
+    friend int  aadd(variant&, const variant& item);
+    friend void aput(variant&, int index, const variant& item);
+    friend void ains(variant&, int index, const variant& item);
+    friend void adel(variant&, int index);
+    friend const variant& aget(const variant&, int index);
+    friend string 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(); }
+
+
+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 evariant: public exception
+{
+protected:
+public:
+    evariant(const char* msg): exception(msg)  {}
+    evariant(const string& msg): exception(msg)  {}
+    virtual ~evariant();
+};
+
+
+
+// -------------------------------------------------------------------- //
+// --- pre-2.0 compatibility declarations ----------------------------- //
+// -------------------------------------------------------------------- //
+
+
+#ifdef PTYPES19_COMPAT 
+
+// ptypes-1.9 objlist and strlist: accept only 'unknown' and
+// derivatives as a base type
+
+class objlist: public tobjlist<unknown>
+{
+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 strlist: public tstrlist<unknown>
+{
+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 strmap: public tstrlist<unknown>
+{
+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 X> 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 -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/index.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/index.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,94 @@ + + + +PTypes + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ + + + + + + + + + + + + + +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/inet.examples.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/inet.examples.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,332 @@ + + + +PTypes: networking: examples + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Networking: +Examples

+


+Example 1
. A simple IP client that tries to retrieve the main page at www.yahoo.com via an HTTP request.

+
+
+#include <pinet.h>
+
+USING_PTYPES
+
+int main()
+{
+    ipstream client("www.yahoo.com", 80);
+
+    try
+    {
+        client.open();
+
+        // send a valid HTTP/1.1 request
+        client.put("GET / HTTP/1.1\r\n"
"Accept: * /*\r\n"
"User-Agent: TestAgent/1.0\r\n"
"Host: www.yahoo.com\r\n"
"Connection: close\r\n\r\n"); + client.flush(); + + // receive the response and print it line by line + while (!client.get_eof()) + pout.putline(client.line()); + + client.close(); + } + catch(estream* e) + { + perr.putf("Error: %s\n", pconst(e->get_message())); + delete e; + } + + return 0; +}
+
+

Example 2 . This example demonstrates the basic usage of streaming network +interfaces ipstream and ipstmserver. +It consists of two programs: test client and test server. The +server handles requests that contain a single word "Hello" by sending +a response greeting back to the client. This example would work for named pipes +as well, i.e. if you replace the class names ipstream +and ipstmserver with namedpipe +and npserver and fix the construction parameters.

+

Client:

+
+
+#include <pinet.h>
+
+USING_PTYPES
+
+const int testport = 8085;
+const int maxtoken = 4096;
+
+int main()
+{
+    // create a client socket and send a greeting to the server
+    // assuming that the server is on the same host (127.0.0.1)
+
+    ipstream client(ipaddress(127, 0, 0, 1), testport);
+
+    try
+    {
+        client.open();
+
+        pout.put("Sending a request to the server...\n");
+        client.putline("Hello");
+        client.flush();
+
+        // receive the response
+        string rsp = client.line(maxtoken);
+        pout.putf("Received: %s\n", pconst(rsp));
+
+        // need to close the socket explicitly to gracefully shutdown 
+        // the peer host too. otherwise, ~ipstream() will call cancel()
+        // and leave the peer in a waiting state (not forever though).
+        client.close();
+    }
+    catch(estream* e)
+    {
+        perr.putf("Error: %s\n", pconst(e->get_message()));
+        delete e;
+    }
+
+    return 0;
+}
+
+

 

+

Server:

+
+
+#include <ptime.h>
+#include <pinet.h>
+
+USING_PTYPES
+
+const int testport = 8085;
+const int maxtoken = 4096;
+
+void servermain(ipstmserver& svr)
+{
+    ipstream client;
+
+    pout.putf("Ready to answer queries on port %d\n", testport);
+
+    while(true)
+    {
+        // serve() will wait for a connection request and will prepare
+        // the supplied ipstream object for talking to the peer.
+        // note that (unlikely) exceptions thrown in serve() will be 
+        // caught in main()
+        svr.serve(client);
+        
+        // for better performance the server would start a new thread
+        // for each client request. for simplicity, we serve the request
+        // in-place. see multithreading examples for the full multithreaded
+        // server template.
+        if (client.get_active())
+        {
+            try
+            {
+                // read the request line:
+                // real-world network applications should limit input data
+                // to prevent potential denial-of-service attacks
+                string req = lowercase(client.line(maxtoken));
+                if (req == "hello")
+                {
+                    // try to reverse-lookup the client's IP
+                    string host = phostbyaddr(client.get_ip());
+                    if (isempty(host))
+                        host = iptostring(client.get_ip());
+                    
+                    // now send our greeting to the client
+                    client.putline("Hello, " + host + " ("
+                        + iptostring(client.get_ip()) + "), nice to see you!");
+                    client.flush();
+
+                    // log this request
+                    pout.putf("%t  greeting received from %s (%a)\n",
+                        now(), pconst(host), long(client.get_ip()));
+                }
+
+                client.close();
+            }
+            catch(estream* e)
+            {
+                perr.putf("Error: %s\n", pconst(e->get_message()));
+                delete e;
+            }
+        }
+    }
+}
+
+int main()
+{
+    ipstmserver svr;
+
+    try
+    {
+        // bind to all local addresses on port 8085
+        svr.bindall(testport);
+
+        // enter an infinite loop of serving requests
+        servermain(svr);
+    }
+    catch(estream* e)
+    {
+        perr.putf("FATAL: %s\n", pconst(e->get_message()));
+        delete e;
+    }
+
+    return 0;
+}
+
+
+

Example 3 . This example demonstrates the use of message-oriented networking +interfaces ipmessage and ipmsgserver. +The client sends a broadcast message to the local network and waits for a response. +It may retry the request several times.

+

Client:

+
+
+#include <pinet.h>
+
+USING_PTYPES
+
+const int testport = 8085;
+const int maxtoken = 4096;
+
+const int tries = 3;
+const int firsttimeout = 2000;
+
+
+bool dorequest(int timeout)
+{
+    ipmessage msg(ipbcast, testport);
+
+    try
+    {
+        pout.put("Broadcasting a request...\n");
+        msg.send("Hello");
+
+        // wait for a response the specified amount of time
+        if (!msg.waitfor(timeout))
+            return false;
+        
+        ipaddress src;
+        string rsp = msg.receive(maxtoken, src);
+        pout.putf("Received: '%s' (from %a)\n", pconst(rsp), long(src));
+    }
+    catch(estream* e)
+    {
+        perr.putf("Error: %s\n", pconst(e->get_message()));
+        delete e;
+    }
+    
+    return true;
+}
+
+
+int main()
+{
+    int timeout = firsttimeout;
+    for (int i = 0; i < tries; i++)
+    {
+        if (dorequest(timeout))
+            break;
+        // double the timeout value
+        timeout *= 2;
+    }
+
+    return 0;
+}
+
+
+

 

+

Server:

+
+
+#include <ptime.h>
+#include <pinet.h>
+
+USING_PTYPES
+
+const int testport = 8085;
+const int maxtoken = 4096;
+
+
+void servermain(ipmsgserver& svr)
+{
+    pout.putf("Ready to answer queries on port %d\n", testport);
+
+    bool quit = false;
+    do
+    {
+        try
+        {
+            // receive the "hello" request and send a simple answer
+            // back to the client
+            string req = lowercase(svr.receive(maxtoken));
+            if (req == "hello")
+            {
+                string host = svr.get_host();
+                if (isempty(host))
+                    host = iptostring(svr.get_ip());
+
+                svr.send("Hello, " + host + " ("
+                    + iptostring(svr.get_ip()) + "), nice to see you!");
+
+                // log this request
+                pout.putf("%t  greeting received from %s (%a)\n",
+                    now(), pconst(host), long(svr.get_ip()));
+            }
+        }
+        catch(estream* e)
+        {
+            perr.putf("Server error: %s\n", pconst(e->get_message()));
+            delete e;
+        }
+        
+    } while (!quit);
+}
+
+
+int main()
+{
+    ipmsgserver svr;
+
+    try
+    {
+        svr.bindall(testport);
+
+        // try to listen on socket once to generate an error right away,
+        // before entering the main server loop
+        svr.poll();
+
+        // enter an infinite loop of serving requests
+        servermain(svr);
+    }
+    catch(estream* e)
+    {
+        perr.putf("FATAL: %s\n", pconst(e->get_message()));
+        delete e;
+    }
+
+
+    return 0;
+}
+
+
+

See also: ipstream, ipstmserver, +ipmessage, ipmsgserver, +Utilities, Multithreading +examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/inet.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/inet.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,55 @@ + + + +PTypes: networking + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Networking

+ +

PTypes' networking module provides simple means of creating both client and +server applications communicating over a IP network. The networking classes and +utilities are built on top of BSD sockets and WinSock2 frameworks. PTypes not +only solves and hides all incompatibility issues between these two API's, but +also makes the task of creating networking applications even simpler.

+

Building client/server applications requires you to either use an existing +protocol (such like HTTP, FTP, SMTP) or develop your own high-level communication +protocol for your specific needs. Since the latter may be a nontrivial task, to +avoid logical mistakes in the communication process we recommend you, first of +all, to study some of the widely used protocols, and second, use one of the existing +protocols with possible modifications instead of creating new ones. For example, +HTTP (Hypertext Transfer Protocol) used by web servers and browsers was designed +to be as generic as possible, so that it can be used virtually for any task with +simple request-response logic.

+

A real-world example of using PTypes networking is included in the source code +(See wshare).

+

The networking classes and utilities are declared in <pinet.h>.

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/inet.ipmessage.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/inet.ipmessage.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,138 @@ + + + +PTypes: networking: ipmessage + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Networking: +ipmessage

+
+
#include <pinet.h>
+
+class ipmessage {
+    ipmessage();
+    ipmessage(ipaddress ip, int port);
+    ipmessage(string host, int port);
+
+    bool   waitfor(int timeout);
+    void   send(const char* buf, int count);
+    void   send(string s);
int receive(char* buf, int count [, ipaddress& src ] ); + string receive(int max [, ipaddress& src ] ); + + ipaddress get/set_ip(); + string get/set_host(); + int get/set_port(); + ipaddress get_myip(); + int get_myport(); + + virtual void sockopt(int socket); +}
+
+

The ipmessage class implements connectionless, unreliable +datagram communication between IP hosts. The underlying protocol (UDP) never guarantees +that a message will be delivered, however, in return, it has +the ability to send broadcast messages on a local network. Unlike stream-oriented +protocols which have some traffic overhead because of the control packets (for +opening/closing connections and for confirming each delivery), message-oriented +protocols always send a single packet, sometimes fragmented if it exceeds the +size of a physical frame.

+

In summary, message-oriented communication is useful in the following situations:

+ +

The maximum message size is limited to 64 KBytes on most systems. Note however, +that sending large messages may result in fragmentation and hence a lesser probability +that the whole message will be delivered. You may assume that a maximum data size +for a UDP message is 1472 bytes, even though such message may still be fragmented +when transferred over a non-Ethernet medium. The size of a guaranteed indivisible +UDP packet is 512 bytes on all physical media types.

+

For larger data chunks you may consider using streaming protocols, since the +TCP control traffic overhead is insignificant compared to data in such cases.

+

The ipmessage and ipmsgserver +classes are not compatible with PTypes streaming interfaces due to unreliable +and connectionless nature of the underlying protocol. These classes provide a +pair of low-level methods receive() and send() +and require that the client (ipmessage) first call send() +prior to receiving, and the server (ipmsgserver) must +first receive data prior to sending. In addition, the server object can be polled +for pending data (optionally with timed waiting) using poll().

+

The ipmessage class is reusable, i.e. you may use +one object to send data to multiple destinations by changing the ip +(or host) and port properties.

+

Ipmessage can generate exceptions of type (estream*) +with a corresponding error code and a message string.

+

(See also Example 3 in Examples)

+

ipmessage::ipmessage() is the default constructor.

+

ipmessage::ipmessage(ipaddress ip, int port) constructs +an ipmessage object and assigns the peer ip/port +values. To send a broadcast message to all hosts on a local network, assign a +predefined constant ipbcast to ip.

+

ipmessage::ipmessage(string host, int port) constructs +an ipmessage object and assigns the peer host name and +port values. Before actually sending data first time, the object resolves the +host name to a numeric IP address. Host can be either +a symbolic DNS name or a numeric address in a string form (e.g. "somehost.com" +or "192.168.1.1").

+

bool ipmessage::waitfor(int milliseconds) waits on +a socket until data is available for reading (returns true) +or the time specified has elapsed, in which case it returns false.

+

ipmessage::send(const char* buf, int count) sends +data to the peer. Ip/host +and port properties must be assigned prior to calling +send(). A client must first call send() +before receiving data from the peer.

+

ipmessage::send(string s) works like the previous +version of send() except that it sends the string s +(not including the terminating null-symbol).

+

int ipmessage::receive(char* buf, int count [, ipaddress& +src ] ) reads data from the socket. Receive() +may hang if no data is available for reading. This function returns the actual +number of bytes read. If the packet received exceeds the size of the supplied +buffer, an exception is raised with code EMSGSIZE. You may check if there is data +available for reading without 'hanging' using waitfor() +described above. The last optional parameter src receives +the IP address of the host that sent this packet: it may be useful if the packet +is received in response to a broadcast request.

+

string ipmessage::receive(int max [, ipaddress& src ] +) works like the previous version of receive() +except that it returns data in a dynamic string. The parameter max +specifies the limit which may not be exceeded when reading data from the network, +like with the previous version of receive().

+

ipaddress ipmessage::get/set_ip() sets/retrieves the +peer address in a numerical form. If the object was constructed using a symbolic +name, get_ip() may perform a DNS lookup (only once). +To send a broadcast message to all hosts on a local network, assign a predefined +constant ipbcast to this property.

+

string ipmessage::get/set_host() sets/retrieves the +peer address in a symbolic form. If the object was constructed using a numeric +IP address, get_host() may perform a reverse DNS lookup.

+

int ipmessage::get/set_port() sets/retrieves the peer +port number.

+

ipaddress ipmessage::get_myip() returns the local +address associated with the socket.

+

int ipmessage::get_myport() returns the local port +number associated with the socket.

+

virtual void ipmessage::sockopt(int socket) - override this method in a descendant class if you want to set up additional socket options (normally, by calling setsockopt()).

+

See also: ipmsgserver, +Utilities, Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/inet.ipmsgserver.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/inet.ipmsgserver.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,105 @@ + + + +PTypes: networking: ipstmserver + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Networking: +ipmsgserver

+
+
#include <pinet.h>
+
+class ipmsgserver {
+    ipmsgserver();
+
+    int bind(ipaddress ip, int port);
+    int bindall(int port);
+
+    bool   poll(int bindnum = -1, int timeout = 0);
+    int    receive(char* buf, int count);
+    string receive(int max);
+    void   send(const char* buf, int count);
+    void   send(string s);
+    void   sendto(const char* buf, int count, ipaddress ip, int port);
+    void   sendto(string s, ipaddress ip, int port)
+
+    ipaddress get_ip();
+    string    get_host();
+
+    virtual void sockopt(int socket);
+}
+
+
+

The ipmsgserver class is used on the server side +of a client-server application. It bounds itself to a specified port/address and +waits until a packet is received from a client host. Once a packet is read with +receive(), subsequent calls to send() +will post data back to the client that sent the last request. Each request must +be fulfilled immediately; unlike the stream-oriented server class, ipmsgserver +can not handle requests concurrently.

+

ipmsgserver can generate exceptions of type (estream*) +with a corresponding error code and a message string.

+

Please, see also the introduction to ipmessage.

+

ipmsgserver::ipmsgserver() constructs an ipmsgserver +object.

+

int ipmsgserver::bind(ipaddress ip, int port) binds +the server to the specified local IP address and port number. This function can +be called multiple times for different local addresses and port numbers. Bind() +returns a value that can be used later in call to poll() +as the parameter bindnum.

+

int ipmsgserver::bindall(int port) binds the server +to all local IP addresses on the specified port number. Can be called multiple +times for different port numbers. Bindall() returns +a value that can be used later in call to poll() as +the parameter bindnum.

+

bool ipmsgserver::poll(int bindnum = -1, int timeout = 0) +polls the listening sockets for data available for reading. Bindnum +specifies the socket number reutrned by bind() or bindall(). +If this parameter is -1 poll() tests all sockets. The +second parameter timeout specifies the amount of time +in milliseconds to wait for data. If timeout is 0 poll() +returns immediately; if it's -1 poll() waits infinitely. +This function returns true if there is data available +for reading.

+

int ipmsgserver::receive(char* buf, int count) reads +data from the socket. Receive() may hang if no data +is available for reading. This function returns the actual number of bytes read. +If the packet received exceeds the size of the supplied buffer, an exception is +raised with code EMSGSIZE. You may check if there is data available for reading +without 'hanging' using poll() described above.

+

string ipmsgserver::receive(int max) works like the +previous version of receive() except that it returns +data in a dynamic string. The parameter max specifies +the limit which may not be exceeded when reading data from the network, like with +the previous version of receive().

+

void ipmsgserver::send(const char* buf, int count) +sends data to the peer. The destination address is determined from the last packet +read using receive().

+

void ipmsgserver::send(string s) works like the previous +version of send() except that it sends the string s +(not including the terminating null-symbol).

+

void ipmsgserver::sendto(const char* buf, int count, ipaddress ip, int port) +sends data to the specified address and port.

+

void ipmsgserver::sendto(string s, ipaddress ip, int port) works like the previous +version of send() except that it sends the string s +(not including the terminating null-symbol).

+

ipaddress ipmsgserver::get_ip() returns the IP address +of the peer. The information about the peer is determined during a successful +call to receive().

+

string ipmsgserver::get_host() returns the peer host +name. A reverse DNS lookup may be performed if necessary. The information about +the peer is determined during a successful call to receive().

+

virtual void ipmsgserver::sockopt(int socket) - override this method in a descendant class if you want to set up additional socket options (normally, by calling setsockopt()).

+

See also: ipmessage, Utilities, +Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/inet.ipstmserver.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/inet.ipstmserver.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,78 @@ + + + +PTypes: networking: ipstmserver + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Networking: +ipstmserver

+
+
#include <pinet.h>
+
+class ipstmserver {
+    ipstmserver();
+
+    int bind(ipaddress ip, int port);
+    int bindall(int port);
+
+    bool poll(int bindnum = -1, int timeout = 0);
+    bool serve(ipstream& client, int bindnum = -1, int timeout = -1);
+
+    virtual void sockopt(int socket);
+}
+
+

The ipstmserver class is used on the server side +of a stream-oriented client-server application. It bounds itself to a specified +port/address and waits until a connection request is received from a client host. +For each connection request a server application performs some actions and returns +to the waiting state. For better performance your daemon may start a new thread +for each client connection.

+

Ipstmserver can generate exceptions of type (estream*) +with a corresponding error code and a message string.

+

ipstmserver::ipstmserver() constructs an ipstmserver +object.

+

int ipstmserver::bind(ipaddress ip, int port) binds +the server to the specified local IP address and port number. This function can +be called multiple times for different local addresses and port numbers. Bind() +returns a value that can be used later in call to poll() +and serve() as the parameter bindnum.

+

int ipstmserver::bindall(int port) binds the server +to all local IP addresses on the specified port number. Can be called multiple +times for different port numbers. Bindall() returns +a value that can be used later in call to poll() and +serve() as the parameter bindnum.

+

bool ipstmserver::poll(int bindnum = -1, int timeout = 0) +polls the listening sockets for connection requests. Bindnum +specifies the socket number reutrned by bind() or bindall(). +If bindnum is -1 poll() tests +all sockets. The second parameter timeout specifies +the amount of time in milliseconds to wait for a connection request. If timeout +is 0 poll() returns immediately; if it's -1 poll() +waits infinitely. This function returns true if there +is a new connection request waiting for processing.

+

bool ipstmserver::serve(ipstream& client, int bindnum += -1, int timeout = -1) polls the specified bound sockets for connection +requests. If there is a connection request, serve() +opens and prepares the supplied ipstream object for +communicating with the client, i.e. client will be active +upon return from serve() and will contain the peer IP +address and the port number. The meanings of bindnum +and timeout are the same as for poll() +except that the default value for timeout in this case +is -1, i.e. wait infinitely. This function returns true +if there is a new connection request and client is active, +or false if the call has timed out.

+

virtual void ipstmserver::sockopt(int socket) - override this method in a descendant class if you want to set up additional socket options (normally, by calling setsockopt()).

+

See also: ipstream, Utilities, +Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/inet.ipstream.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/inet.ipstream.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,106 @@ + + + +PTypes: networking: ipstream + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Networking: +ipstream

+
+
#include <pinet.h>
+
+class ipstream: instm, outstm {
+    ipstream();
+    ipstream(ipaddress ip, int port);
+    ipstream(string host, int port);
+    ~ipstream();
+
+    void open();
+    void close();
+    void cancel();
+    bool waitfor(int milliseconds);
+
+    ipaddress get/set_ip();
+    string    get/set_host();
+    int       get/set_port();
+    ipaddress get_myip();
+    int       get_myport();
+
+    virtual void sockopt(int socket);
+}
+
+

The ipstream class implements full-duplex streaming +communication between IP hosts. Ipstream incorporates +iobase, instm +and outstm interfaces and adds two more properties: +peer IP address and peer port number. This means, you can work with ipstream +the same way you work with infile and outfile, +except that you specify the target IP address or the symbolic hostname along with +the port number instead of the filename when constructing an object. Besides, +the rules of object-oriented inheritance allow you to manipulate ipstream +objects in those parts of your code which are only 'familiar' with the basic instm +and outstm interfaces.

+

In order to open a connection and exchange data you need to set target (peer +host) address and the port number. The peer address can be either a symbolic DNS +name or a numeric IPv4 address. Regardless of which one of these two properties +you set first, the ipstream object can perform DNS resolving +as necessary and return both properties on your request.

+

Ipstream adds the following status codes: IO_RESOLVING, +IO_RESOLVED, IO_CONNECTING, IO_CONNECTED (see also iobase +for the status codes common to all streams).

+

On UNIX the library startup code blocks SIGPIPE, +so that all error conditions on sockets always raise exceptions of type (estream*).

+

ipstream::ipstream() is the default constructor.

+

ipstream::ipstream(ipaddress ip, int port) constructs +an ipstream object and assigns the peer ip/port +values.

+

ipstream::ipstream(string host, int port) constructs +an ipstream object and assigns the peer host name and +port values. Before actually opening the stream ipstream +resolves the host name to a numeric IP address. Host +can be either a symbolic DNS name or even a numeric address in a string form (e.g. +"somehost.com" or "192.168.1.1").

+

ipstream::~ipstream() cancels the connection immediately +and destroys the object. To shut down the connection 'gracefully' you should call +close() before destroying the object or before the program +goes beyond the scope of a static/local ipstream object.

+

void ipstream::open() opens a connection with the +peer. host or ip along with +port properties must be set before opening the stream.

+

void ipstream::close() closes the stream 'gracefully', +and in some situations may be time-consuming. Although all stream objects in PTypes +are closed by the destructors automatically, it is recommended to explicitly +call close() for socket objects.

+

void ipstream::cancel() closes the stream immediately. +If the connection was successful, calling cancel() may +leave the peer host in a waiting state for a long time.

+

bool ipstream::waitfor(int milliseconds) waits on +the socket until either data is available for reading (returns true) +or the time specified in the parameter has elapsed, in which case it returns false.

+

ipaddress ipstream::get/set_ip() sets/retrieves the +peer address in a numerical form. If the object was constructed using a symbolic +name, get_ip() may perform a DNS lookup (only once).

+

string ipstream::get/set_host() sets/retrieves the +peer address in a symbolic form. If the object was constructed using a numeric +IP address, get_host() may perform a reverse DNS lookup.

+

int ipstream::get/set_port() sets/retrieves the peer +port number.

+

ipaddress ipstream::get_myip() returns the local address +associated with the socket.

+

int ipstream::get_myport() returns the local port +number associated with the socket.

+

virtual void ipstream::sockopt(int socket) - override this method in a descendant class if you want to set up additional socket options (normally, by calling setsockopt()).

+

See also: iobase, instm, +outstm, ipstmserver, +Utilities, Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/inet.utils.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/inet.utils.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,49 @@ + + + +PTypes: networking: utilities + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Networking: +Utilities

+
+
#include <pinet.h>
+
+string     iptostring(ipaddress ip);
+ipaddress  phostbyname(const string& name);
+string     phostbyaddr(ipaddress ip);
+string     phostcname(const string& name);
+
+
+

Many PTypes networking utility functions and class methods manipulate a new +data type ipaddress - IPv4 (4-byte) internetwork address +type. The objects of this type can be constructed either by explicitly specifying +the 4 bytes separately (e.g. ipaddress(192, 168, 1, 1)) +or by assigning another ipaddress. The objects of this +type are mutually compatible with unsigned long type, +however, you can not rely on the order of bytes if an ipaddress +is converted to a unsigned long and vice versa. This +implicit typecast is provided only for comparing an ipaddress +value with 0 or ipnone (see Examples).

+

string iptostring(ipaddress ip) converts an IP address +to a string, e.g. ipaddress(127, 0, 0, 1) would be "127.0.0.1".

+

ipaddress phostbyname(const string& name) resolves +a symbolic DNS name or a numeric IP addresses to ipaddress. +On error this function returns ipnone.

+

string phostbyaddr(ipaddress ip) performs reverse +DNS lookup for the given IP address. On error this function returns an empty string.

+

string phostcname(const string& name) returns +the canonical name of the host. On error this function returns an empty string.

+

See also: ipstream, ipstmserver, +Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/intro.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/intro.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,168 @@ + + + +PTypes: introduction + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Introduction

+ +


+ Basic features

+ +


+ Why use PTypes?

+
+

PTypes is yet another generic class library among tens and hundreds of others. + To find its own niche in this variety of generic programming tools we decided + to emphasis on simplicity of the interfaces and readability of the resulting + code (i.e. the code that uses the library). The library focuses + only on most widely used data types and functional interfaces. We think that + like programming languages themselves, low-level libraries, too, should use + the minimal set of notions for covering most programming patterns.

+ +

Some data types in the library (strings, character sets and variants) use algebraic +notation rather than object-oriented, i.e. you write length(s) +for a string object instead of s.length(). We believe +that traditional notation better fits to a class that represents some fundamental +notion and is not supposed to produce subclasses with overridden methods. In other +words, if there is no inheritance and polymorphism, there is no need for method +calls as well.

+

PTypes uses old-fashioned all-lowercase naming style, since it can + peacefully co-exist with other styles in one program. Whether you are a `unixoid' + or you are using modern writing styles (Hungarian, Borland, etc.) you can + combine your favorite style with PTypes with no or very little harm to your + source code.

+

And finally, in order to achieve better readability of the resulting + code we use + clean + class + naming, + i.e. the string type is called string, thread + is thread, + etc.

+

We designed this library in the hope that PTypes with its conciseness and + intuitiveness could find its own 'target audience'.

+
+


+ Versions and availability

+
+ +

Version 2.1 of PTypes is the eleventh public release. The third number in the +version indicates insignificant improvements or bug fixes. You might want to take +a look at the Changes page if you are familiar with +one of the previous versions.

+ +

The latest source code and both on-line and out-of-line documentation can be +found at

+
+ +

http://www.melikyan.com/ptypes/

+
+

You can receive announcements about new releases through one of the following + services:

+
+

Subscribe to the project + at freshmeat.net
+ Monitor the project + at SourceForge.net

+
+ +

The development version of PTypes is available at SourceForge.net's CVS server. +If you are willing to join the development of the library, please become a SourceForge.net +user and then contact me to get full access to the CVS repository. The file TODO +in the development branch contains the immediate development plan for the library.

+
+


+ Bugs and known problems

+
+

The list of problems encountered in the latest version along with their + solutions, if available, can be found at PTypes project management page (at + SourceForge.net):

+
+

PTypes project management + page

+
+
+


+ Contributors

+
+

We would like to thank:

+
+

Pierre-Frederic Caillaud <peufeu at free dot fr>
+Ralph Siemsen <ralphs at netwinder dot org>
+Marco Geri <m.geri at list dot it>
+Philippe Le Rohellec <plerohel at hotmail dot com>
+Mark Lentczner <markl at glyphic dot com>
+Jordan Ritter <jpr5 at darkridge dot com>
+Sergey Matveychuk <sem at ciam dot ru>

+
+
+


+ Contacts

+
+

PTypes is open and free, which also means it is open to your comments and + suggestions. Please, submit bug reports and feature requests through PTypes + project management page at sf.net. There is a public discussion + forum for general questions.

+

The author would be grateful if you let him know that you use the library + in your project. The author's email address is:

+
+

Hovik Melikyan <h at melikyan dot com>

+
+
+

See also: Compiling and Porting, Changes, Resources

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/lists.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/lists.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,93 @@ + + + +PTypes: lists + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +Lists

+ +


+PTypes offers a set of list templates/classes that were designed to eliminate +the template 'code bloat' problem and also to allow reallocating of dynamic arrays +in the most efficient way.

+

Why not STL containers? Or, why there is no universal container for +arbitrary types, like std::vector, in PTypes? There are 3 main reasons for this:

+ + + +


+Overview of PTypes list templates. As a replacement of a universal vector-like +container PTypes offers two separate templates: tpodlist +and tobjlist. Each of them have certain limitations +in return for the following advantages: dynamic arrays are reallocated in the most +efficient way, templates produce no or very little code during instantiation.

+

The tpodlist template is intended for use with small +POD (plain-old-data) objects. For bigger structures or for arbitrary non-POD types +in general the library offers a list of pointers, tobjlist, +that has the ability to automatically destroy objects when they are removed from +the list. Tobjlist never reallocates items themselves, +instead, it only deals with pointers.

+

As a universal way of holding string/object pairs in an indexed list the library +offers the tstrlist template. When constructed as a +sorted list, this template can also serve as a map indexed by textual keys. And +finally, the textmap class provides a simple interface +for mapping strings to strings, i.e. textual keys to values.

+

Historically, PTypes was using list classes that required the list item to +be derived from unknown. These list classes (objlist, +strlist and strmap) are still present in the library for backward compatibility. +There is no such limitation in the newer versions of the library, however, deriving +your classes from unknown can still give you an advantage +of automatically detecting memory leaks in your program.

+

Bounds checking. All list operations that involve indexes can be checked +for validity at run-time. If an index value is invalid, the library generates +an unrecoverable (fatal) error. Bounds checking is done when compiling your code +in debug mode (i.e. if macro DEBUG is defined). You +may also enable it explicitly for your release builds by defining CHECK_BOUNDS. +Note that the bounds checking code is fully inlined and the library itself is +not affected by these macros.

+

The list class family is declared in <ptypes.h>.

+

See also: unknown

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/lists.textmap.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/lists.textmap.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,57 @@ + + + +PTypes: lists: textmap + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +Lists: textmap

+
+
+class textmap {
+    textmap(bool casesens = false);
+    int    get_count() const;
+    void   pack();
+    void   clear();
+    int    put(string key, string value);
+    string operator [](int index) const;
+    string operator [](string key) const;
+    string getkey(int index) const;
+}
+
+
+


+The textmap class implements an associative array of +strings, i.e. textual key/value pairs. Items in a textmap +object can be accessed both via integral indexes and textual keys. Internally, +textmap keeps the list sorted in alphabetical order +and uses binary search to find keys in a list.

+

The methods get_count(), clear() +and pack() work as for tobjlist +and are not described in this section.

+

textmap::textmap(bool casesens = false) constructs +a textmap object, optionally with case-sensitive key search.

+

int textmap::put(string key, string value) associates +value with key. This method +can either insert or replace an existing value, as well as remove it from a textmap +if value is an empty string.

+

string textmap::operator [](string key) returns a +value associated with the key, or an empty string if +key does not exist in a textmap.

+

string textmap::operator [](int index) returns a value +at the position index. This method along with get_count() +can be used to iterate through a textmap.

+

string textmap::getkey(int index) returns the key +value at the position index.

+

See also: tstrlist

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/lists.tobjlist.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/lists.tobjlist.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,107 @@ + + + +PTypes: lists: tobjlist + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +Lists: tobjlist

+
+
template <class X> class tobjlist {
+    tobjlist(bool ownobjects = false);
+    ~tobjlist();
+
+    int   get/set_count(int);
+    int   get/set_capacity(int);
+    bool  get/set_ownobjects(bool);
+
+    void  ins(int index, X* obj);
+    void  add(X* obj);
+    X*    operator [](int index) const;
+    X*    top() const;
+    void  put(int index, X* obj);
+    void  del(int index);
+    X*    pop();
+
+    void  clear();
+    void  pack();
+
+    bool  search(const void* key, int& index) const;
+    virtual int compare(const void* key, const void* obj) const;
+}
+
+


+The tobjlist template implements a dynamic array of +pointers to objects of an arbitrary type X. Since the +list itself only holds pointers to objects, the element type can be any structure, +including a class with constructors and destructors. The element type is not required +to have a copy constructor. A list can contain objects of any derivative class +of X as well.

+

Tobjlist can optionally (with ownobjects += true) be responsible for freeing objects whenever +they are removed from a list, in which case the objects are required to be dynamically +allocated with operator new. Objects can be automatically +freed by the following methods: set_count() if the new +value is less than the old one, also del(), clear(), +put() and ~tobjlist().

+

tobjlist::tobjlist(bool ownobjects = false) constructs +a tobjlist object. See note for the parameter ownobjects +above.

+

tobjlist::~tobjlist() calls clear() +and destroys the list object.

+

int tobjlist::get/set_count(int) gets or sets the +number of items in a list. If the new value for count +is greater than the old one, all new slots are filled with NULL pointers. If it's +smaller and if ownobjects is true, extra objects are +freed.

+

int tobjlist::get/set_capacity(int) gets or sets the +capacity of a list. The capacity property reflects the +number of slots actually allocated for a list and is set automatically by other +methods whenever necessary. Like tpodlist, tobjlist +uses a 'lazy allocation' technique (see also tpodlist::get/set_capacity).

+

bool tobjlist::get/set_ownobjects(bool) returns or +sets the ownobjects flag.

+

void tobjlist::ins(int index, X* obj) inserts the +object obj into a list at the position index. +All pointers with greater indexes are moved up to make room for the new pointer.

+

void tobjlist::add(X* obj) adds the object obj +to the end of a list.

+

X* tobjlist::operator [](int index) returns the pointer +to an object at the position index.

+

X* tobjlist::top() returns the last pointer in a list.

+

void tobjlist::put(int index, X* obj) replaces the +pointer at the position index with obj. +Can free the old object if ownobjects is true.

+

void tobjlist::del(int index) deletes the pointer +at the position index and moves all pointers with greater +indexes down. Can also free the object if ownobjects +is true.

+

X* tobjlist::pop() returns the last pointer in a list +and deletes it from a list.

+

void tobjlist::clear() deletes all pointers from a +list. Can also free all objects if ownobjects is true.

+

void tobjlist::pack() sets capacity +equal to count. You can call pack() +after deleting multiple pointers from a list to optimize memory usage.

+

bool tobjlist::search(const void* key, int& index) +performs binary search on a list. The virtual method compare() +(below) must be overridden in order for search() to +work.

+

virtual int tobjlist::compare(const void* key, const void* +obj) override this method in a descendant class to be able to perform binary +search on a list. The value of key is the same as in +the call to search(). Obj +is a pointer to an object that must be compared against key. +The return value must be -1, 0 or 1, similarly to the function strcmp().

+

See also: tpodlist, tstrlist

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/lists.tpodlist.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/lists.tpodlist.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,105 @@ + + + +PTypes: lists: tpodlist + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +Lists: tpodlist

+
+
template <class X, bool initzero = false> class tpodlist {
+    tpodlist();
+
+    tpodlist& operator =(const tpodlist& t);
+
+    int  get/set_count(int);
+    int  get/set_capacity(int);
+
+    X&   ins(int index);
+    void ins(int index, const X& item);
+    void ins(int index, const tpodlist& t);
+    X&   add();
+    void add(const X& item);
+    void add(const tpodlist& t);
+    X&   operator [](int index);
+    const X& operator [](int index) const;
+    X&   top();
+    void del(int index, int count = 1);
+    void pop();
+
+    void clear();
+    void pack();
+}
+
+


+The tpodlist template implements a dynamic array of +so-called POD (plain-old-data) objects. POD types in C++ are: all integral types, +pointers, floating point types, and also compound types (i.e. arrays and structures) +that contain only POD items. With optimizing compilation, the instantiation of +this template produces no extra code.

+

The parameter X of this template specifies the element +type for the list. The optional parameter initzero indicates +whether the memory allocated for new elements should be initialized to zero in +methods ins(int), add() and +set_count(int).

+

tpodlist::tpodlist() is the default constructor.

+

tpodlist& tpodlist::operator =(const tpodlist& t) +is an assignment operator that clears a list and then copies all items from t.

+

int tpodlist::get/set_count(int) gets or sets the +number of items in a list.

+

int tpodlist::get/set_capacity(int) gets or sets the +capacity of a list. The capacity property reflects the +number of items actually allocated for a list and is set automatically by other +methods whenever necessary. Tpodlist uses a 'lazy allocation' +technique for better performance: when items are added with add() +or ins(), the capacity grows in bigger increments. This +property, however, does not change when you delete items from a list, with only +exception when count becomes 0, in which case capacity +is also set to 0. You can call pack() to optimize memory +usage after deleting multiple items. Setting capacity +to a value less than count is an error.

+

X& tpodlist::ins(int index) allocates a slot for +a new item at the position index and returns a reference +to the slot. All items with greater indexes are moved up to make room for the +new item. The slot can be initialized to zero if the template parameter initzero +was true. Calling ins() with +index equal to count is equivalent +to calling add().

+

void tpodlist::ins(int index, const X& item) inserts +item at index.

+

void tpodlist::ins(int index, const tpodlist& t) +inserts all items of the list t at the position index.

+

X& tpodlist::add() allocates a slot for a new +item at the end of a list and returns a reference to the slot.

+

void tpodlist::add(const X& item) appends item +to a list.

+

void tpodlist::add(const tpodlist& t) appends +the list t to a given list.

+

X& tpodlist::operator [](int index) returns a +reference to an item at the position index. A const +version of this operator also exists.

+

X& tpodlist::top() returns a reference to the +last item (one that has the greatest index) in a list.

+

void tpodlist::del(int index, int count = 1) deletes +count items from a list and moves all items with greater +indexes down. The parameter count is optional and defaults +to 1.

+

void tpodlist::pop() deletes the last item from a +list.

+

void tpodlist::clear() deletes all items from a list +and also sets capacity to 0.

+

void tpodlist::pack() sets capacity +equal to count. You can call pack() +after deleting multiple items from a list to optimize memory usage.

+

See also: tobjlist

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/lists.tstrlist.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/lists.tstrlist.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,128 @@ + + + +PTypes: lists: tstrlist + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +Lists: tstrlist

+
+
template <class X> class tstrlist {
+    tstrlist(int flags = 0);
+    ~tstrlist();
+
+    int    get/set_count(int);
+    int    get/set_capacity(int);
+    bool   get/set_ownobjects(bool);
+    void   clear();
+    void   pack();
+
+    bool   get_sorted() const;
+    bool   get_duplicates() const;
+    bool   get_casesens() const;
+
+    // methods that work both on sorted and unsorted lists
+    void   ins(int index, string key, X* obj);
+    void   put(int index, string key, X* obj);
+    void   put(int index, X* obj);
+    int    add(string key, X* obj);
+    X*     operator [](int index) const;
+    string getkey(int index) const;
+    void   del(int index);
+    int    indexof(string key) const;
+    int    indexof(void* obj) const;
+
+    // these methods are allowed only on sorted lists
+    int    put(string key, X* obj);
+    X*     operator [](string key) const;
+    void   del(string key);
+    bool   search(string key, int& index) const;
+}
+
+


+The tstrlist template is similar to tobjlist +in many ways, except that it maintains pairs of strings and objects of type X, +and defines some additional methods described below. Tstrlist +can optionally be sorted by string keys, which allows to use it as an associative +array of objects. Thus, tstrlist combines functionality +of an indexed dynamic array and an associative array at the same time. Like tobjlist, +tstrlist can 'own objects', which means it can automatically +free objects whenever they are removed from a list.

+

The methods get/set_count(), get/set_capacity(), +get/set_ownobjects(), clear() +and pack() work as for tobjlist +and are not described in this section.

+

tstrlist::tstrlist(int flags = 0) constructs a tstrlist +object. The parameter flags can be a combination of +the following constants:

+ +

void tstrlist::ins(int index, string key, X* obj) +inserts a key/object pair into a list at the position index. +For sorted lists index must be equal to the value returned +by search() for the given key. +A common pattern of using ins() on sorted lists is to +call search() for a key to determine whether an object +associated with a given key exists, then either insert a new object at the position +pointed to by search() or to get the existing object +at that position.

+

void tstrlist::put(int index, string key, X* obj) +puts (replaces) the key/object pair at the position index.

+

void tstrlist::put(int index, X* obj) puts obj +at the position index. The key at this position remains +unchanged.

+

int tstrlist::add(string key, X* obj) on sorted lists +this method performs search and inserts the key/object pair at a proper position +to keep the list in a sorted order. For ordinary (unsorted) lists this method +adds the key/object pair at the end of a list.

+

X* tstrlist::operator [](int index) returns an object +at the position index.

+

string tstrlist::getkey(int index) returns the key +value at the position index.

+

void tstrlist::del(int index) deletes the key/object +pair at the position index.

+

int tstrlist::indexof(string key) determines the index +of a given key. This function performs binary search +on sorted lists, or otherwise linear search on unsorted lists. Returns -1 if key +is not found.

+

int tstrlist::indexof(void* obj) determines the index +of a given object. Always uses linear search. Returns -1 if obj +is not found.

+

int tstrlist::put(string key, X* obj) is a universal +method of adding, replacing and removing objects in a sorted list. Put() +performs search by a given key and inserts obj +if the key doesn't exist in a list, replaces the old object with obj +if the key was found in a list, or deletes the key/object pair if the parameter +obj was NULL.

+

X* tstrlist::operator [](string key) returns an object +associated with a given key. Works only on sorted lists. +Returns NULL if key is not found.

+

void tstrlist::del(string key) deletes the key/object +pair for a given key. Works only on sorted lists.

+

bool tstrlist::search(string key, int& index) +performs binary search on a list. Returns true if key +is present in a list. The output parameter index contains +either the position at which key was found, or otherwise +the position where key must be inserted to preserve +the sorted order.

+

See also: tobjlist, textmap

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/portability.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/portability.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,86 @@ + + + +PTypes: Portability and Performance Issues + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Portability and performance issues

+


+ 64-bit integers: most compilers provide long long +type modifier for declaring 64-bit integers, but at least two of them, Microsoft +C/C++ and Borland C/C++, use quite unaesthetic keyword __int64. +PTypes offers its own wrapper type large (in <pport.h>), +which is a portable signed 64-bit integer. Unsigned large +or ularge are also available. For portable 64-bit string +conversions use itostring() and stringto*() +declared in <ptypes.h>.

+

Another incompatibility exists for printf-style formatted output routines: +Windows uses "I64" type modifier for 64-bit integers, whereas standard-compliant +libraries recognize "ll" (ell-ell). PTypes solves this problem in its +outstm::putf() method: you can safely use "ll" +modifier on all platforms.

+

End-of-line sequences: PTypes input stream routines automatically recognize +three types of EOL sequences: LF (UNIX), CR (Mac) and CR-LF (DOS/Win) and set +instm::eol property accordingly.

+

As for output streams, unlike many Windows-based C run-time libraries, PTypes +does NOT make any translations and always sends your data as is. In order to generate +an EOL sequence appropriate to the target platform (i.e. the system your application +is running on), use outstm::puteol() and outstm::putline(string). +Some protocols and data formats, however, require some predetermined EOL sequence +regardless of the target platform, e.g. HTTP always uses CR-LF, PostScript uses +CR, etc. In such cases you can use standard C escape sequences to send appropriate +codes to the output stream, e.g. "\r\n" or "\r".

+

File names: you can always use UNIX-style path names (with slash '/') +when working with files through PTypes streaming classes. Since drive specifiers +in path names are specific only to Windows, try to use relative paths in your +program whenever possible. For additional notes on pipe naming, please see introduction +for the namedpipe class.

+

Arithmetic operations and multithreading: a simple increment and decrement +operation (i++ and i--) in a multithreaded application may NOT be thread-safe +on most RISC CPU's and on i386-based multiprocessor systems. Even if you are not +interested in the resulting value of an increment/decrement operation, still use +PTypes pincrement() and pdecrement() +on variables shared between threads.

+

Performance of dynamic strings: most of the string operations rely on +dynamic memory reallocation. PTypes tries to avoid frequent use of physical reallocation +by aligning the dynamic string buffers on 16, 32, 64 ... 4096-byte boundaries, +depending on the logical size of a string. Physical reallocation highly depends +on the performance of the standard realloc() function, +which may vary from OS to OS. Linux, for example, performs reallocations up to +30 times faster than Windows on a similar computer. PTypes dynamic strings also +depend on the performance of the atomic increment and decrement functions (see +below).

+

Performance of atomic increment/decrement/exchange operations: on SPARC, PowerPC +and i386-based platforms PTypes implements atomic operations using CPU instructions. On all other platforms these operations use slower mutex +locking (see src/patomic.cxx).

+

Reentrancy of synchronization objects: the POSIX standard does not specify +whether synchronization objects should be reentrant or not. For instance, if you +use recursive locks on a mutex object the behaviour of your application may vary +on different systems. Most POSIX systems, such like Linux, provide a faster but +non-reentrant implementation of synchronization primitives.

+

Read/write lock portability issues: the rwlock +class is built on top of the POSIX rwlock interface, wherever available, or uses +the internal implementation (see src/rwlock.cxx). Various +system-level implementations use different prioritization schemes: they may be +'fair' with respect to both reader and writer threads, or a higher priority may +be given to one of them. Unfortunately the behaviour of rwlock is not standardized +yet. PTypes' internal implementation uses the 'fair' scheme which we believe is +the best and the only DoS-proof (denial-of-service) among other algorithms. On +the other hand, replacing the system-level rwlock with our own implementation +on all systems would lead to a preformance penalty compared to using 'native' +objects. We set this issue aside for some time and we are open to discuss it with +interested/experienced developers.

+

See also: String Conversion, +outstm, namedpipe, +string, Multithreading Utilities

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/ref.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/ref.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,560 @@ + + + +PTypes: INDEX + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: INDEX

+
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
aclearvariant: arrays +
aclonevariant: arrays +
addrefunknown & component +
anextvariant: arrays +
assigncset: manipulation +
asstringcset: manipulation +
clearcset: manipulation +
clearstring: manipulation +
clearvariant: utilities +
component::addnotificationunknown & component +
component::~componentunknown & component +
component::delnotificationunknown & component +
component::freenotifyunknown & component +
comprefunknown & component +
concatstring: manipulation +
containsstring: manipulation +
copystring: manipulation +
cset::csetcset: constructors +
dayofweekdate/time: calendar +
daysdate/time: datetime +
daysinmonthdate/time: calendar +
daysinyeardate/time: calendar +
decodedatedate/time: calendar +
decodetimedate/time: time +
delstring: manipulation +
delvariant: arrays +
dttostringdate/time: datetime +
encodedatedate/time: calendar +
encodetimedate/time: time +
excludecset: manipulation +
fillcset: manipulation +
getvariant: arrays +
includecset: manipulation +
infile::get/set_filenamestreams: infile +
infile::infilestreams: infile +
infile::pipestreams: infile +
inmemory::get/set_strdatastreams: inmemory +
inmemory::inmemorystreams: inmemory +
insstring: manipulation +
instm::getstreams: instm +
instm::get_eofstreams: instm +
instm::get_eolstreams: instm +
instm::linestreams: instm +
instm::previewstreams: instm +
instm::putbackstreams: instm +
instm::readstreams: instm +
instm::skiplinestreams: instm +
instm::skiptokenstreams: instm +
instm::tokenstreams: instm +
iobase::cancelstreams: iobase +
iobase::closestreams: iobase +
iobase::get/set_activestreams: iobase +
iobase::get/set_bufsizestreams: iobase +
iobase::get/set_cancelledstreams: iobase +
iobase::get/set_onstatusstreams: iobase +
iobase::get_statusstreams: iobase +
iobase::get_streamnamestreams: iobase +
iobase::openstreams: iobase +
iobase::seekstreams: iobase +
iobase::seekxstreams: iobase +
iobase::tellstreams: iobase +
iobase::tellxstreams: iobase +
ipmessage::get_myipnetworking: ipmessage +
ipmessage::get_myportnetworking: ipmessage +
ipmessage::get/set_hostnetworking: ipmessage +
ipmessage::get/set_ipnetworking: ipmessage +
ipmessage::get/set_portnetworking: ipmessage +
ipmessage::ipmessagenetworking: ipmessage +
ipmessage::receivenetworking: ipmessage +
ipmessage::sendnetworking: ipmessage +
ipmessage::sockoptnetworking: ipmessage +
ipmessage::waitfornetworking: ipmessage +
ipmsgserver::bindnetworking: ipstmserver +
ipmsgserver::bindallnetworking: ipstmserver +
ipmsgserver::get_hostnetworking: ipstmserver +
ipmsgserver::get_ipnetworking: ipstmserver +
ipmsgserver::ipmsgservernetworking: ipstmserver +
ipmsgserver::pollnetworking: ipstmserver +
ipmsgserver::receivenetworking: ipstmserver +
ipmsgserver::sendnetworking: ipstmserver +
ipmsgserver::sendtonetworking: ipstmserver +
ipmsgserver::sockoptnetworking: ipstmserver +
ipstmserver::bindnetworking: ipstmserver +
ipstmserver::bindallnetworking: ipstmserver +
ipstmserver::ipstmservernetworking: ipstmserver +
ipstmserver::pollnetworking: ipstmserver +
ipstmserver::servenetworking: ipstmserver +
ipstmserver::sockoptnetworking: ipstmserver +
ipstream::cancelnetworking: ipstream +
ipstream::closenetworking: ipstream +
ipstream::get_myipnetworking: ipstream +
ipstream::get_myportnetworking: ipstream +
ipstream::get/set_hostnetworking: ipstream +
ipstream::get/set_ipnetworking: ipstream +
ipstream::get/set_portnetworking: ipstream +
ipstream::ipstreamnetworking: ipstream +
ipstream::~ipstreamnetworking: ipstream +
ipstream::opennetworking: ipstream +
ipstream::sockoptnetworking: ipstream +
ipstream::waitfornetworking: ipstream +
iptostringnetworking: utilities +
isdatevaliddate/time: calendar +
isemptystring: manipulation +
isleapyeardate/time: calendar +
istimevaliddate/time: time +
isvaliddate/time: datetime +
isXXXvariant: utilities +
itostringstring: conversion +
jobqueue::get_countmultithreading: jobqueue +
jobqueue::get_limitmultithreading: jobqueue +
jobqueue::getmessagemultithreading: jobqueue +
jobqueue::jobqueuemultithreading: jobqueue +
jobqueue::postmultithreading: jobqueue +
jobqueue::posturgentmultithreading: jobqueue +
lengthstring: manipulation +
logfile::logfilestreams: logfile +
logfile::putfstreams: logfile +
lowercasestring: conversion +
message::idmultithreading: message +
message::messagemultithreading: message +
message::parammultithreading: message +
message::resultmultithreading: message +
mkdtdate/time: datetime +
msecsdate/time: datetime +
msgqueue::defhandlermultithreading: msgqueue +
msgqueue::get_countmultithreading: msgqueue +
msgqueue::get_limitmultithreading: msgqueue +
msgqueue::msghandlermultithreading: msgqueue +
msgqueue::msgqueuemultithreading: msgqueue +
msgqueue::postmultithreading: msgqueue +
msgqueue::posturgentmultithreading: jobqueue +
msgqueue::posturgentmultithreading: msgqueue +
msgqueue::processmsgsmultithreading: msgqueue +
msgqueue::processonemultithreading: msgqueue +
msgqueue::runmultithreading: msgqueue +
msgqueue::sendmultithreading: msgqueue +
mutex::entermultithreading: mutex +
mutex::leavemultithreading: mutex +
mutex::lockmultithreading: mutex +
mutex::mutexmultithreading: mutex +
mutex::unlockmultithreading: mutex +
namedpipe::get/set_pipenamestreams: namedpipe +
namedpipe::namedpipestreams: namedpipe +
nowdate/time: datetime +
nowstringdate/time: datetime +
npserver::npserverstreams: npserver +
npserver::servestreams: npserver +
outfile::get/set_appendstreams: outfile +
outfile::get/set_filenamestreams: outfile +
outfile::get/set_umodestreams: outfile +
outfile::outfilestreams: outfile +
outmd5::get_bindigeststreams: outmd5 +
outmd5::get_digeststreams: outmd5 +
outmd5::outmd5streams: outmd5 +
outmemory::get_strdatastreams: outmemory +
outmemory::outmemorystreams: outmemory +
outstm::flushstreams: outstm +
outstm::get/set_flusheolstreams: outstm +
outstm::putstreams: outstm +
outstm::puteolstreams: outstm +
outstm::putfstreams: outstm +
outstm::putlinestreams: outstm +
outstm::writestreams: outstm +
pdecrementmultithreading: utils +
pexchangemultithreading: utils +
phostbyaddrnetworking: utilities +
phostbynamenetworking: utilities +
phostcnamenetworking: utilities +
pincrementmultithreading: utils +
posstring: manipulation +
psleepmultithreading: utils +
pthrequalmultithreading: utils +
pthrselfmultithreading: utils +
putvariant: arrays +
releaseunknown & component +
rwlock::rdlockmultithreading: rwlock +
rwlock::rwlockmultithreading: rwlock +
rwlock::unlockmultithreading: rwlock +
rwlock::wrlockmultithreading: rwlock +
scopelock::scopelockmultithreading: mutex +
scopelock::~scopelockmultithreading: mutex +
scoperead::scopereadmultithreading: rwlock +
scoperead::~scopereadmultithreading: rwlock +
scopewrite::scopewritemultithreading: rwlock +
scopewrite::~scopewritemultithreading: rwlock +
semaphore::postmultithreading: semaphore +
semaphore::semaphoremultithreading: semaphore +
semaphore::signalmultithreading: semaphore +
semaphore::waitmultithreading: semaphore +
setlengthstring: manipulation +
stringstring: constructors/destructors +
stringtoistring: conversion +
stringtoiestring: conversion +
stringtouestring: conversion +
textmap::[]lists: textmap +
textmap::getkeylists: textmap +
textmap::putlists: textmap +
textmap::textmaplists: textmap +
thread::cleanupmultithreading: thread +
thread::executemultithreading: thread +
thread::get_finishedmultithreading: thread +
thread::get_idmultithreading: thread +
thread::get_runningmultithreading: thread +
thread::get_signaledmultithreading: thread +
thread::relaxmultithreading: thread +
thread::signalmultithreading: thread +
thread::startmultithreading: thread +
thread::threadmultithreading: thread +
thread::~threadmultithreading: thread +
thread::waitformultithreading: thread +
timedsem::timedsemmultithreading: semaphore +
timedsem::waitmultithreading: semaphore +
tobjlist::[]lists: tobjlist +
tobjlist::addlists: tobjlist +
tobjlist::clearlists: tobjlist +
tobjlist::comparelists: tobjlist +
tobjlist::dellists: tobjlist +
tobjlist::get/set_capacitylists: tobjlist +
tobjlist::get/set_countlists: tobjlist +
tobjlist::get/set_ownobjectslists: tobjlist +
tobjlist::inslists: tobjlist +
tobjlist::packlists: tobjlist +
tobjlist::poplists: tobjlist +
tobjlist::putlists: tobjlist +
tobjlist::searchlists: tobjlist +
tobjlist::tobjlistlists: tobjlist +
tobjlist::~tobjlistlists: tobjlist +
tobjlist::toplists: tobjlist +
tpexchangemultithreading: utils +
tpodlist::=lists: tpodlist +
tpodlist::[]lists: tpodlist +
tpodlist::addlists: tpodlist +
tpodlist::clearlists: tpodlist +
tpodlist::dellists: tpodlist +
tpodlist::get/set_capacitylists: tpodlist +
tpodlist::get/set_countlists: tpodlist +
tpodlist::inslists: tpodlist +
tpodlist::packlists: tpodlist +
tpodlist::poplists: tpodlist +
tpodlist::toplists: tpodlist +
tpodlist::tpodlistlists: tpodlist +
trigger::postmultithreading: trigger +
trigger::resetmultithreading: trigger +
trigger::signalmultithreading: trigger +
trigger::triggermultithreading: trigger +
trigger::waitmultithreading: trigger +
tstrlist::[]lists: tstrlist +
tstrlist::addlists: tstrlist +
tstrlist::dellists: tstrlist +
tstrlist::getkeylists: tstrlist +
tstrlist::indexoflists: tstrlist +
tstrlist::inslists: tstrlist +
tstrlist::putlists: tstrlist +
tstrlist::searchlists: tstrlist +
tstrlist::tstrlistlists: tstrlist +
tzoffsetdate/time: datetime +
tzupdatedate/time: datetime +
uniquestring: manipulation +
unit::cleanupunit +
unit::connectunit +
unit::mainunit +
unit::rununit +
unit::uinunit +
unit::uoutunit +
unit::waitforunit +
utodatetimedate/time: datetime +
variant::[]variant: arrays +
vartypevariant: utilities +
+

+
+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/ref.tmpl.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/ref.tmpl.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,23 @@ + + + +PTypes: INDEX + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: INDEX

+
+

+%REF% +

+
+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/source-forge-logo.png Binary file doc/source-forge-logo.png has changed diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.errors.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.errors.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,56 @@ + + + +PTypes: streams: error handling + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +Error handling

+

When a recoverable error occurs during input/output operations, an exception +of type (estream*) is thrown. The exception object +contains an error message which can be shown to the user. The message is accessible +through estream::get_message().

+

The example below shows how to catch an exception and recover normal execution +of the program:

+
+
#include <pstreams.h>
+
+USING_PTYPES
+
+infile f("somefile.txt");
+try 
+{
+    f.open();
+    while(!f.get_eof())
+        // read the file...
+}
+catch (estream* e) 
+{
+    perr.putline(e->get_message());
+    delete e;
+}
+
+
+

The estream class provides a system error code in +UNIX errno semantics through estream::get_code(). On +Windows most error codes are translated into corresponding UNIX errno codes. Less +frequently occurring errors are translated to a generic errno code EIO. When an +estream object returns EIO, the actual message string +is constructed based on the status code of the stream. For example, if the status +code was IO_OPENING, the error code was EIO, the message would be "Couldn't +open [filename]". For explanations on what each errno code means, +see comments in src/piobase.cxx source file.

+

Estream also provides a reference to the stream object +that raised the error condition through estream::get_errstm().

+

See also: iobase, Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.examples.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.examples.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,114 @@ + + + +PTypes: streams: examples + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +Examples

+

Example 1. This simple program creates a new file and writes a string +to it.

+
+
#include <pstreams.h>
+
+USING_PTYPES
+
+int main() 
+{
+    // the outfile object is declared and constructed outside 
+    // the try...catch clause, since the exception object
+    // contains a reference to the stream that caused the error.
+    // besides, stream constructors and destructors in PTypes 
+    // never throw exceptions.
+    outfile f(fname);
+
+    f.set_bufsize(1024);             // the default value in this version is 8192
+
+    try 
+    {
+        f.open();
+        f.put("This is a test file.");
+        f.close();
+    }
+    catch (estream* e) 
+    {
+        perr.putf("File error: %s\n", e->get_message());
+        delete e;
+    }
+    return 0;
+}
+
+
+
+

Example 2. This program reads a C source, extracts identifiers and builds +a usage dictionary. It does not understand C comments and string literals though, +but can be easily improved to understand them too.

+
+
#include <ptypes.h>
+#include <pstreams.h>
+
+USING_PTYPES
+
+const cset letters("_A-Za-z");
+const cset digits("0-9");
+const cset identchars = letters + digits;
+const cset otherchars = !letters;
+
+void main(int argc, char* argv[]) 
+{
+    tstrlist<void*> dic(SL_SORTED | SL_CASESENS);
+
+    infile f(argv[1]);
+
+    try 
+    {
+        f.open();
+
+        while (!f.get_eof()) 
+        {
+            char c = f.preview();
+
+            // a C identifier begins with a letter
+            if (c & letters)
+            {
+                // ... and may contain letters and digits
+                string ident = f.token(identchars);
+                int i;
+                if (!dic.search(ident, i))
+                    dic.ins(i, ident, 0);
+            }
+
+            else
+                // ignore everything else
+                f.skiptoken(otherchars);
+        }
+
+    }
+
+    catch (estream* e) 
+    {
+        pout.putf("Error: %s\n", e->get_message());
+        delete e;
+    }
+
+    // now print the dictionary
+    for (int i = 0; i < dic.get_count(); i++)
+        pout.putline(dic.getkey(i));
+}
+
+
+

See also: iobase, instm, +infile, outstm, +outfile, Error +handling

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,91 @@ + + + +PTypes: streams + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams

+ +

The stream input/output module, which is an integral part of PTypes, declares +a family of classes that implement abstract functionality of stream-oriented data +processing. The main features of this module include:

+ +

The basic class iobase encapsulates features +common to both input and output, such like buffering, event and error handling, +etc. This class is derived from component. Two descendant +classes -- instm and outstm +-- specialize in data input and output respectively, as well as provide simple +and powerful text processing utility methods.

+

PTypes declares three built-in objects for standard +input, output and error devices.

+

All recoverable error conditions generate exceptions of class (estream*). +See Error handling for details.

+

Some encapsulated structure fields in this module are accessed through get_X() +and set_X() function pairs. To simplify documentation, +we use a single description in the form get/set_X() +for such fields, and sometimes we refer to them as properties.

+

The stream i/o class family is declared in <pstreams.h>.

+

See also: Networking

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.infile.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.infile.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,47 @@ + + + +PTypes: streams: infile + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +infile

+
+
#include <pstreams.h>
+
+class infile: instm {
+    infile( [ const string& filename ] );
+    void pipe(outfile& peer);
+    string get/set_filename(string);
+}
+
+
+

This class derives all public methods and properties from iobase +and instm, and in addition, defines the following:

+

infile::infile( [ const string& filename ] ) creates +an input file stream, but does not open the file. Filename +is optional and can be set later, using set_filename().

+

void infile::pipe(outfile& peer) creates a local +pipe. This function sets up and opens the infile and +outfile objects so that a thread can asynchronously +pass data to another thread within one process. Note that pipe() +opens both streams; subsequent calls to open(), close() +or cancel() shuts down the pipe. Local pipe is a slower +alternative to the message queue. The only advantage of local pipes is that they +provide a standard streaming interface.

+

string infile::get/set_filename(string) sets the +file name. set_filename() closes the stream prior to +assigning the new value.

+

See also: iobase, instm, +Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.inmem.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.inmem.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,38 @@ + + + +PTypes: streams: inmemory + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +inmemory

+
+
#include <pstreams.h>
+
+class inmemory: instm {
+    inmemory(string mem);
+    string get/set_strdata(string);
+}
+
+

Use inmemory to read data from a dynamic memory buffer +by means of the streaming interface. Inmemory is derived +from instm.

+

inmemory::inmemory(string mem) - constructs an inmemory +object. The string passed through the mem parameter +will be used by this object as a data source.

+

string inmemory::get/set_strdata(string) - gets or +sets the memory buffer. Set_strdata() closes the stream +prior to assigning the new value.

+

See also: iobase, instm +

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.instm.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.instm.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,106 @@ + + + +PTypes: streams: instm + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +instm

+
+
#include <pstreams.h>
+
+class instm: iobase {
+    bool   get_eof();
+    bool   get_eol();
+    char   preview();
+    char   get();
+    void   putback();
+    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);
+    void   skipline();
+    void   skiptoken(const cset& chars);
+    int    skip(int numbytes);
+    int    read(char* buf, int count);
+}
+
+
+

This class implements the basic functionality of input streams. Instm +is derived from iobase and inherits all its +public methods and properties. All methods of instm +except read() and get_eof() +require buffering.

+

bool instm::get_eof() returns true +if the end of file is reached.

+

bool instm::get_eol() returns true +if the file pointer is currently at the end of a line. Since operating systems +use different end-of-line codes or combinations of codes, it is recommended to +check the end-of-line status using this property and skip the end-of-line sequence +by calling skipline() method.

+

char instm::preview() returns the next character +from the stream but does not advance the file pointer. If the pointer is at the +end of file, preview() returns eofchar +(null character).

+

char instm::get() returns the next character from +the stream. If an attempt is made to read beyond the file (i.e. if the property +eof is set), this method returns eofchar +(null character).

+

void instm::putback() puts the last retrieved character +back to the stream; a faster equivalent to seek(-1, IO_CURRENT). +This function can be called only after a call to get() +if the latter did not return an eof character.

+

string instm::token(const cset& chars [, int limit ] ) +reads the next token that only contains characters of the given set chars. +The optional parameter limit specifies the maximum number +of bytes to read. If the token exceeds the limit, an exception (estream*) +is thrown with error number ERANGE.

+

int instm::token(const cset& chars, char* buf, int size) +-- this version of token() reads the next token to the +given buffer buf. The number of characters is limited +to size. This method returns the actual number of characters +read from the stream which can not be greater than size. +Unlike the other version of token(), does not throw +exceptions if the token exceeds the limit, but rather truncates it to size. +Note: this function does not put a terminating null symbol in the buffer.

+

string instm::line( [ int limit ] ) reads the current +line from the stream. The end-of-line code(s) are not included in the returning +value, however, line() skips them and sets the file +pointer at the beginning of the next line. The optional parameter limit +specifies the maximum number of bytes to read. If the token exceeds the limit, +an exception (estream*) is thrown with error number +ERANGE.

+

int instm::line(char* buf, int size) -- this version +of line() reads the next line from the stream to the +buffer buf. The number of characters is limited to size. +This method returns the actual number of characters read from the stream which +can not be greater than size. Unlike the other version +of line(), does not throw exceptions if the token exceeds +the limit, but rather truncates it to size. Note: this +function does not put a terminating null symbol in the buffer.

+

void instm::skiptoken(const cset& chars) works like +previous versions of token() except that the token string +is not returned. Can be safely used to skip very large tokens.

+

void instm::skipline() skips the current line and +sets the file pointer at the beginning of the next line.

+

int instm::skip(int numbytes) skips the specified +number of bytes from the input stream.

+

int instm::read(char* buf, int count) reads count +bytes from the stream and stores them in the buffer buf. + Returns the number of bytes actually read. This method does +not require buffering.

+

See also: iobase, outstm, +string, cset, Error +handling

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.iobase.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.iobase.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,85 @@ + + + +PTypes: streams: iobase + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +iobase

+
+
#include <pstreams.h>
+
+typedef void (*iostatusevent)(iobase* sender, int code);
+
+class iobase {
+    void   open();
+    void   close();
+    void   cancel();
+    large  tellx();
+    int    tell();
+    large  seekx(large newpos, ioseekmode mode = IO_BEGIN);
+    int    seek(int newpos, ioseekmode mode = IO_BEGIN);
+    string get_streamname();
+    bool   get/set_active(bool);
+    bool   get/set_cancelled(bool);
+    int    get/set_bufsize(int);
+    int    get_status();
+    iostatusevent get/set_onstatus(iostatusevent);
+}
+
+
+

The methods and properties of this abstract class are common to all stream +interfaces in PTypes.

+

void iobase::open() opens (activates) the stream.

+

void iobase::close() closes (deactivates) the stream. +This method is called automatically during destruction of an object. Close() +calls flush() for output streams. To simplify error +handling in user programs, this method never throws exceptions. If you want to +check for errors during the last write operation, call flush() +explicitly before closing the stream.

+

void iobase::cancel() closes the stream and sets the +cancelled property to true. In communication streams +this method may close the connection immediately, unlike close(), +which always tries to flush data buffers and then close the stream gracefully.

+

large iobase::tellx() returns either the current position +in the target media (usually file) or, for communication channels, the number +of bytes transfered from the beginning of the session.

+

int iobase::tell() left for compatibility; returns a 32-bit file offset or raises an exception if the value doesn't fit the int type.

+

large iobase::seekx(large newpos, ioseekmode mode = IO_BEGIN) changes the media pointer (e.g. file pointer). Possible values for mode are: IO_BEGIN, IO_CURRENT and IO_END. This function first tries to position the +stream pointer within the scope of the I/O buffer. If the new pointer is out of +buffer's range, seekx() then tries to change the physical +pointer of the target media. Note that physical positioning is not supported by +some stream types, e.g. by ipstream.

+

int iobase::seek(int newpos, ioseekmode mode = IO_BEGIN) left for compatibility; tries to seek in 32-bit mode and return a 32-bit file offset. Raises an exception if the return value doesn't fir the int type.

+

string iobase::get_streamname() returns a string +containing either a file name, an URL, or some other string describing the underlying +media or object. Useful for diagnostics messages.

+

bool iobase::get/set_active(bool) indicates whether +the stream is active. Setting this property to true +or false opens or closes the stream respectively.

+

bool iobase::get/set_cancelled(bool) returns true +if the stream was closed using cancel().

+

int iobase::get/set_bufsize(int) sets the buffer +size for the stream. Setting this property to -1 will assign some reasonable default +value, which may vary depending on the operating environment, available memory, +etc. Note: text input routines require buffering (see instm).

+

int iobase::get_status(int) returns the current status +of the stream. The value of this property can be one of the following: IO_CREATED, +IO_OPENING, IO_OPENED, IO_READING, IO_WRITING, IO_EOF, IO_CLOSING, IO_CLOSED. +Derivative classes may add other status codes, e.g. see ipstream.

+

iostatusevent iobase::get/set_onstatus(iostatusevent) +-- sets or returns user-defined callback function. The callback function is called +whenever the status of the stream is changed (see also get_status()).

+

See also: instm, outstm, +Error handling

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.logfile.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.logfile.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,48 @@ + + + +PTypes: streams: logfile + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +logfile

+
+
#include <pstreams.h>
+
+class logfile: outfile {
+    logfile( [ const string& filename, bool append = true ] );
+    void putf(const char* fmt, ...);
+}
+
+
+

The lofgile class inherits all public methods and +properties from outfile, but differs in the +following:

+ +

logfile::logfile( [ const string& filename, bool append += true ] ) creates an output file stream, but does not open the file. When +opening a file with open(), the file pointer is positioned +at the end of the file, unless append is set to false. +Filename and append parameters +are optional.

+

void logfile::putf(const char* fmt, ...) is a thread-safe +version of outstm::putf().

+

See also: iobase, outstm, +outfile, Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.md5.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.md5.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,76 @@ + + + +PTypes: streams: outmd5 + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +outmd5

+
+
#include <pstreams.h>
+
+class outmd5: outstm {
+    outmd5();
+    outmd5(outstm* outthru);
+    string get_digest();
+    const unsigned char* get_bindigest();
+}
+
+
+

MD5, the message digest algorithm described in RFC 1321, computes a 128-bit +sequence (sometimes called 'message digest', 'fingerprint' or 'MD5 checksum') +from arbitrary data. As stated in RFC 1321, it is conjectured that it is computationally +infeasible to produce two messages having the same message digest, or to produce +any message having a given prespecified target message digest. MD5 can be viewed +as a one-way encryption system and can be used, for example, to encrypt passwords +in a password database.

+

The MD5 fingerprint is more often converted to so-called ASCII-64 form in order +to conveniently store it in plain text environments and protocols. Thus, the 128-bit +binary sequence becomes a 22-character text string consisting of letters, digits +and two special symbols '.' and '/'. (Note that this is not the same as Base64 +encoding in MIME).

+

In order to compute a MD5 fingerprint you first create a stream object of type +outmd5 and then send data to it as if it was an ordinary +output file or a socket stream. After you close the stream, you can obtain the +fingerprint in ASCII-64 form using the object's get_digest() +method.

+

The implementation of MD5 is derived from L. Peter Deutsch's work.

+

This class derives all public methods and properties from iobase +and outstm, and in addition defines the following:

+

outmd5::outmd5() creates a bufferless MD5 stream.

+

outmd5::outmd5(outstm* outthru) creates a MD5 stream +and attaches an output stream outthru to it. Everything +sent to the MD5 stream will also be duplicated to outthru. +You may want, for example, to attach perr to your MD5 +stream for debugging purposes.

+

string outmd5::get_digest() closes the stream and +returns the computed fingerprint in text form (ASCII-64).

+

const unsigned char* outmd5::get_bindigest() closes +the stream and returns a pointer to a 16-byte buffer with the binary MD5 fingerprint.

+

Example:

+
+
+string cryptpw(string username, string password)
+{
+    outmd5 m;
+    m.open();
+    m.put(username);
+    m.put(password);
+    m.put("Banana with ketchup");
+    return m.get_digest();
+}
+
+
+

See also: iobase, outstm +

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.namedpipe.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.namedpipe.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,96 @@ + + + +PTypes: streams: namedpipe + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +namedpipe

+
+
#include <pstreams.h>
+
+class namedpipe: instm, outstm {
+    namedpipe( [ string pipename ] );
+    string get/set_pipename(string);
+}
+
+
+

The namedpipe class implements full-duplex streaming +communication between processes, typically on one computer. It is built on top +of Windows named pipes and local UNIX sockets. Namedpipe +incorporates iobase, instm +and outstm interfaces and adds one more property: +the pipe name to connect to. PTypes named pipes are session-oriented.

+

Naming. Local sockets on UNIX can be created anywhere in the file system +and generally behave like ordinary files, except that the input and output streams +for a socket file is handled by the server process that created the socket. In +contrast to UNIX, Windows allocates named pipes in a special directory (actually +a share name) \\.\pipe, which is not visible to the +end-user.

+

PTypes can accept both a file name and an absolute path name when creating +a named pipe object, however, absolute paths have effect only on UNIX. If you +specify a single file name on UNIX, PTypes will place the socket file in /tmp. +That is, if you are writing a portable application, and you want the socket file +to be placed in a directory other than /tmp on UNIX +(e.g. some daemons running as root place their sockets in /var/run), +you can specify the full path in both Windows and UNIX versions of your program: +the library will ignore the path on Windows, since it can not place it other than +in \\.\pipe, and will use it on UNIX.

+

Usage. Named pipes provide efficient means of interprocess communication. +Many networking applications, typically SQL servers, offer both network sockets +and local sockets as alternate ways of connecting to the service. For security +reasons, a system administrator may choose to configure the service such that +it will use only the local socket, or the service can be open to the network too +if it provides strong authentication at application level.

+

Namedpipe and ipstream +classes are compatible: both are full-duplex streams and are derived from instm +and outstm simultaneously. Thus, PTypes allows you to +easily combine both methods of communication in one application. Each thread serving +connections on server-side of your application can accept two parameters of basic +types instm and outsm; you +can then pass either an ipstream or a namedpipe +object (or any other compatible stream object) to the newly instantiated thread +to serve the request coming from the client. Note that it is sometimes necessary +to provide explicit typecast when assigning namedpipe +or ipstream to outstm or instm.

+

Windows security note. Named pipes on Windows are open to the network, +i.e. any computer can connect to a pipe through \\computer-name\pipe\..., +where computer-name can be a NetBIOS name or even an IP address. Even though +PTypes' interfaces do not allow you to connect to a remote named pipe for the +sake of compatibility with UNIX, still, you should consider a situation when someone +knowing the pipe name and the protocol you use, writes his own program to 'illegally' +access your service on a Windows machine from a remote computer. Hence, for better +security, your service should provide user authentication at application level +(of course, unless it's a public service and is open anyway). Aside from security, +network named pipes are much slower than any other networking protocol, such like +TCP/IP, so we do not encourage using named pipes remotely in any case.

+

Unlike Windows, UNIX local sockets can never be accessed from a remote computer +even through a NFS-mounted directory. Note that remote access to named pipes on +Windows can be disabled by stopping all Windows networking services and leaving +only the transport-level protocol stacks.

+

Local unnamed pipes for exchanging data within one process can be created using +infile::pipe().

+

Interface. Namedpipe is compatible with iobase, +instm and outstm +and in addition, defines the following:

+

namedpipe::namedpipe( [ string pipename ] ) creates +a named pipe object and optionally assigns the pipe name. When creating a namedpipe +object that will be passed to npserver::serve(), it +is not necessary to assign a pipe name.

+

string namedpipe::get/set_pipename(string) gets or +sets the pipe name. When assigning a new pipe name, set_pipename() +first closes the stream.

+

See also: npserver, iobase, +instm, outstm, +Networking examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.npserver.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.npserver.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,49 @@ + + + +PTypes: streams: npserver + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +npserver

+
+
#include <pstreams.h>
+
+class npserver {
+    npserver(string pipename);
+    bool serve(namedpipe& client, int timeout = -1);
+}
+
+

The npserver class is used on the server side of +an interprocess communication channel. It listens to connections on the specified +named pipe or a local UNIX socket and for each connection provides a namedpipe +object for exchanging data with the peer.

+

Please, read the introduction to namedpipe +first.

+

npserver::npserver(string pipename) creates a named +pipe server object. The named pipe or a local socket is actually created during +the first call to serve() for this object.

+

bool npserver::serve(namedpipe& client, int timeout = +-1) polls the pipe for connection requests. If there is a connection request +from a client, serve() opens and prepares the supplied +namedpipe object for communicating with the client, i.e. client +will be active upon return from serve(). The second +optional parameter timeout specifies the amount of time +in milliseconds to wait for a connection request. If timeout is 0 serve() +will return immediately; if it's -1 serve() will wait +infinitely. This function returns true if there is a +connection request and the client object is active, +or false if the call has timed out.

+

See also: namedpipe, Networking +examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.outfile.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.outfile.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,50 @@ + + + +PTypes: streams: outfile + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +outfile

+
+
#include <pstreams.h>
+
+class outfile: outstm {
+    outfile( [ const string& filename, bool append = false ] );
+
+    string get/set_filename(string);
+    bool   get/set_append(bool);
+    int    get/set_umode(int);
+}
+
+
+

This class derives all public methods and properties from iobase +and outstm, and in addition defines the following:

+

outfile::outfile( [ const string& filename, bool append += false ] ) creates an output file stream, but does not open the file. +When opening a file with open(), it is truncated to +zero unless append property is set to true. Filename +and append parameters are optional.

+

string outfile::get/set_filename(string) sets the +file name. set_filename() closes the stream prior to +assigning the new value.

+

bool outfile::get/set_append(bool) -- if set to true, +the file pointer is set beyond the last byte of the file when opening the stream +with open().

+

int outfile::get/set_umode(int) sets UNIX file mode +when creating a new file. By default a file is created with 0644 +octal, which on UNIX means read/write access for the owner and read-only access +for group members and all others. This property has no effect on Windows.

+

See also: iobase, outstm, +logfile, Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.outmem.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.outmem.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,38 @@ + + + +PTypes: streams: outmemory + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +outmemory

+
+
#include <pstreams.h>
+
+class outmemory: outstm {
+    outmemory(int limit = -1);
+    string get_strdata();
+}
+
+

Use outmemory to write data to a dynamic memory buffer +by means of the streaming interface. Outmemory is derived +from outstm.

+

outmemory::outmemory(int limit = -1) creates an outmemory +object. The memory buffer grows as data is written to the stream. You can optionally +limit the size of the memory buffer to limit (-1 means +unlimited).

+

string outmemory::get_strdata() returns data written +to the stream as a dynamic string and closes the stream.

+

See also: iobase, outstm +

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.outstm.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.outstm.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,72 @@ + + + +PTypes: streams: outstm + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +outstm

+
+
#include <pstreams.h>
+
+class outstm: iobase {
+    void putf(const char* fmt, ...);
+    void put(char);
+    void put(string);
+    void puteol();
+    void putline(string);
+    int  write(const char* buf, int count);
+    void flush();
+    bool get/set_flusheol(bool);
+}
+
+
+

This class implements the basic functionality of output streams. Outstm +is derived from iobase and inherits all its +public methods and properties.

+

End-of-line sequences are not translated when you send data through the output +methods. To write an end-of-line sequence appropriate to the given operating environment +use puteol() instead.

+

void outstm::putf(const char* fmt, ...) is a printf-style +output method. PTypes supports a subset of format specifiers common to all platforms: +<blank>, '#', '+' and '-' formatting flags, 'L', 'h', 'l' and 'll' format +modifiers, and the following standard format specifiers: cdiouxXeEfgGps. +In addition, PTypes supports a format specifier a for +IP addresses (ipaddress type) and also t +and T for timestamps (datetime +type). Note that some compilers require to explicitly cast ipaddress +arguments to long type, and also string +arguments to const char* (or pconst).

+

void outstm::put(char c) writes the character c +to the stream.

+

void outstm::put(string str) writes the string str +to the stream.

+

void outstm::puteol() writes an end-of-line sequence +to the stream. The actual sequence depends on the platform the library was compiled +on. May flush data if the property flusheol is set to +true.

+

void outstm::putline(string str) writes the string +str to the stream followed by an end-of-line sequence, +as in call to puteol().

+

int outstm::write(const char* buf, int count) writes +count bytes from the buffer buf +to the stream.

+

void outstm::flush() writes the remaining data in +the buffer to the media, if any. This method is called automatically when the +stream is being closed.

+

bool outstm::get/set_flusheol(bool) -- set this property +to true if you want each line to be written to the media or communication stream +immediately. Default is false.

+

See also: iobase, instm, +Error handling

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/streams.stdio.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/streams.stdio.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,37 @@ + + + +PTypes: streams: Standard input, output and error devices + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Streams: +Standard input, output and error devices

+
+
#include <pstreams.h>
+
+instm  pin;
+outstm pout;
+outstm perr;
+outstm pnull;
+
+

PTypes declares four static stream objects for standard input, output, error +and null devices - pin, pout, +perr and pnull respectively. +These objects can be used in place of the standard C or C++ input/output interfaces. +Pnull is an output stream that discards any data written +to it. The putf() method in standard output objects +pout and perr is atomic with +respect to multithreading.

+

See also: iobase, instm, +outstm, Examples

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/string.constructors.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/string.constructors.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,73 @@ + + + +PTypes: string: constructors/destructors + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +string: Constructors/destructors

+
+
#include <ptypes.h>
+
+class string {
+    string();
+    string(const string&);
+    string(char);
+    string(const char*);
+    string(const char*, int);
+    ~string();
+}
+
+
+

A string object can be constructed in 5 different ways:

+ +

Destructor ~string() decrements the reference count +for the given string buffer and removes it from the dynamic memory if necessary.

+

Examples:

+
+
string s1;             // empty string
+string s2 = s1;        // copy
+string s3 = 'A';       // single character
+string s4 = "ABCabc";  // string literal
+char* p = "ABCabc";
+string s5 = p;         // null-terminated string
+string s6(p, 3);       // buffer/length
+
+
+

See also: Operators, Typecasts, +Manipulation, Conversion

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/string.conversion.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/string.conversion.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,82 @@ + + + +PTypes: string: conversion + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +string: Conversion

+
+
#include <ptypes.h>
+
+string itostring(<ordinal> value);
+string itostring(<ordinal> value, int base, int width = 0, char pad = ' ');
+large  stringtoi(const string& s);
+large  stringtoie(const string& s);
+ularge stringtoue(const string& s, int base);
+string lowercase(const string& s);
+
+
+


+PTypes provides 3 different string-to-int conversion functions: stringtoi(), +stringtoie() and stringtoue(). +The first function stringtoi() is for non-negative decimal +numbers; it returns -1 on error. The other two functions with a suffix 'e' in +their names ('e' is for 'exception') may throw exceptions, but they accept the +full range of 64-bit values.

+

These functions replace the CRTL functions atoll() +and strtoll() which are not implemented on all systems.

+

Both function families, string-to-int and int-to-string, accept numeration +bases in the range 2 to 64. The 64-digit numeration uses all digits, letters and +also '.' and '/'. It may be useful for representing, for example, MD5 checksums +in a compact printable form (see function outmd5::get_digest() +in src/pmd5.cxx).
+

+

string itostring(<ordinal> value) converts +the given ordinal value to a string. Various overloaded +versions of this function accept ordinal values of different sizes and signness.

+

string itostring(<ordinal> value, int base, +int width = 0, char pad = ' ') converts an integer value to a string with +the numeration base specified by base, which can be +in the range 2 - 64. To right-justify the resulting string you can specify width +and pad parameters. If the numeration base is greater +than 36 in addition to digits and letters itostring() +uses '.' and '/' characters and also lowercase letters. For numeration bases other +than 10 the parameter value is always treated as unsigned.

+

large stringtoi(const string& s) converts a string +to a 64-bit integer. This function accepts only positive decimal large numbers +and 0. It returns -1 if the string does not represent a valid positive number +or an overflow occurred.

+

large stringtoie(const string& s) converts a string +to a 64-bit integer. This function accepts signed decimal large numbers. +Unlike stringtoi(), this function may throw an exception +of type (econv*) if the string does not represent a +valid number or an overflow occurred.

+

unsigned large stringtoue(const string& s, int base) +converts a string to an unsigned 64-bit integer using the numeration base specified +by base. This function accepts unsigned large numbers. +It may throw an exception of type (econv*) if the string +does not represent a valid number or an overflow occurred. Base +can be in the range 2 - 64. For numeration bases from 2 to 36 this function uses +digits and letters, and the letter case is insignificant. For numeration bases +grater than 36, '.', '/' and lowercase letters are used additionaly.

+

string lowercase(const string& s) converts all +characters of the given string s to lower case. The +current version of the library "understands" only lower ASCII characters; +all other characters remain unchanged. This function can effectively detect if +all characters in the string are already in lower-case to avoid unnecessary string +allocations.

+

See also: Constructors/destructors, +Operators, Typecasts, +Manipulation

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/string.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/string.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,65 @@ + + + +PTypes: string + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +string

+ +

The string class implements dynamically allocated +reference-counted 8-bit character strings. The string +class is a mixture of L-type and null-terminated strings: it has both the length +indicator and the terminating null-symbol. The length of a string is theoretically +limited to INT_MAX, and practically is limited to the +amount of virtual memory space available to the application.

+

A string object itself contains only a reference to the first character of +the string buffer. A string object can be implicitly converted to a null-terminated +string, either a variable or passed as an actual parameter, thus allowing to combine +both PTypes strings and traditional C strings in your application. A string object +converted to char* or const char* +never returns NULL pointers: it guarantees to always +point to some data, even if the string is zero-sized.

+

The reference counting mechanism works transparently (known also as +copy-on-write) and safely with regard to multithreading. You can manipulate +string objects as if each object had its own copy of string data. Whenever you +modify a string object the library safely detaches the buffer from all other string +objects that may be using the same buffer and creates a unique copy so that changes +won't affect the other "holders" of this string.

+

NOTE on multithreading: the dynamic string objects themselves are NOT +thread-safe. In other words, each thread can manipulate objects (variables) of +type string only within their scope. However, it is +safe to pass strings as (copy) parameters when, for example, sending a message +to a concurrent thread through a message queue. Whenever the recipient thread +tries to modify the string, the shared data buffer is safely detached.

+

The string class is declared in <ptypes.h>.

+

See also: Constructors/destructors, +Operators, Typecasts, +Manipulation, Conversion

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/string.manipulation.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/string.manipulation.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,105 @@ + + + +PTypes: string: manipulation + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +string: Manipulation

+
+
#include <ptypes.h>
+
+// get/set length and misc.
+int    length(const string& s);
+char*  setlength(string&, int);
+char*  unique(string&);
+void   clear(string& s);
+bool   isempty(const string& s);
+
+// concatenate
+void   concat(string& s, const char* sc, int catlen);
+
+// copy (get substring by position and length)
+string copy(const string& s, int from [, int cnt ] );
+
+// insert string or character
+void   ins(const char* s1, string& s, int at);
+void   ins(char s1, string& s, int at);
+void   ins(const string& s1, string& s, int at);
+void   ins(const char* s1, int s1len, string& s, int at);
+
+// delete substring
+void   del(string& s, int at [, int cnt ] );
+
+// find substring or character
+int    pos(const char* s1, const string& s);
+int    pos(char s1, const string& s);
+int    pos(const string& s1, const string& s);
+int    rpos(char s1, const string& s);
+
+// compare substring
+bool   contains(const char* s1, const string& s, int at);
+bool   contains(char s1, const string& s, int at);
+bool   contains(const string& s1, const string& s, int at);
+bool   contains(const char* s1, int s1len, const string& s, int at);
+
+
+

int length(const string& s) returns the actual length +of the string, not counting the terminating null-symbol.

+

char* setlength(string&, int) changes the actual length +of the string. The content of the original string is preserved, however the content +of extra characters added during reallocation is undefined. This function returns +a pointer to a unique buffer (i.e. refcount is 1), like function unique() +below. Even if the length of the string is not changing, setlength() +guarantees to make the string unique.

+

char* unique(string&) makes the string buffer unique, +i.e. a new buffer is allocated and data is copied if necessary, so that the reference +count after calling this function is guaranteed to be 1. All string manipulation +functions call unique() whenever a modification is made +on the string buffer. You may need to call this function explicitly to obtain +a character pointer to the buffer; in all other cases reference counting mechanism +works transparently.

+

bool isempty(string&) returns true if the given +string is empty. Using this function is preferable to comparing the string with +empty string literal "".

+

clear(string&) makes the given string empty. Using +this function is preferable to assigning an empty string literal "".

+

concat(string& s, const char* sc, int catlen) adds +the given buffer sc of length catlen +to the string object s. Use operators + and += instead +to concatenate characters, null-terminated strings and string objects.

+

string copy(const string& s, int from [, int cnt ] ) +returns a substring of s starting from position from +and containing cnt characters. If cnt +is omitted, the rest of the string s starting from position +from is returned.

+

ins(..., string& s, int at) inserts a character, a +null-terminated string, a string object or a buffer with specified length into +string object s at the given position at. +If the position is out of bounds, ins() does nothing.

+

del(string& s, int at [, int cnt ] ) deletes cnt +characters starting from position at of the string s. +If cnt is omitted, the rest of the string starting from +at is deleted.

+

int pos(..., const string& s) returns the position +of the first occurrence of a character, a null-terminated string or a string object +(first parameter) in the source string s, or returns +-1 if the substring is not found. Function rpos() performs +reverse-search.

+

bool contains(..., const string& s, int at) returns +true if the given character, null-terminated string or string object (first parameter) +equals the substring of s at the given position at.

+

See also: Constructors/destructors, +Operators, Typecasts, +Conversion

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/string.operators.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/string.operators.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,77 @@ + + + +PTypes: string: operators + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +string: Operators

+
+
#include <ptypes.h>
+
+class string {
+    // assignment
+    string& operator =(const char*);
+    string& operator =(char);
+    string& operator =(const string&);
+    friend void assign(string&, const char* buf, int len);
+
+    // concatenation
+    string& operator +=(const char*);
+    string& operator +=(char);
+    string& operator +=(const string&);
+    string  operator +(const char*) const;
+    string  operator +(char) const;
+    string  operator +(const string&) const;
+    friend  string operator +(const char*, const string&);
+    friend  string operator +(char c, const string&);
+
+    // comparison
+    bool operator ==(const char*) const;
+    bool operator ==(char) const;
+    bool operator ==(const string&) const;
+    bool operator !=(const char*) const;
+    bool operator !=(char c) const;
+    bool operator !=(const string&) const;
+
+    // indexed character access, 0-based
+    char& string::operator[] (int index);
+    const char& string::operator[] (int index) const;
+}
+
+

The string class defines the following binary operators: assignment (=), +concatenation (+), concatenation with assignment (+=) +and comparison (==, !=). At +least one of the operands (either left or right) must be of type string. +Another operand can be one of the following: char, char* +or string.

+

Indexed access operator allows to store or retrieve a value of an individual +character. The index is 0-based. When compiled with either DEBUG +or CHECK_BOUNDS conditional symbol, bounds checking +is performed for the indexed access; if the index is out of bounds (i.e. less +than 0 or equals to or greater than the length of the string), an unrecoverable +error is raised. The non-debugging version of the library never checks for index +overlfows, thus making your program somewhat faster but less safe.

+

Examples

+
+
string s1 = "abc", s2 = 'd', s3;
+
+s3 = s1 + s2;
+s2 += "ef";
+s3[2] = 'B';
+
+
+

See also: Constructors/destructors, +Typecasts, Manipulation, +Conversion

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/string.typecasts.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/string.typecasts.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,67 @@ + + + +PTypes: string: typecasts + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +string: Typecasts

+
+
#include <ptypes.h>
+
+class string {
+    operator (const char*)() const;
+}
+
+

A string object can be assigned to a variable or passed as an actual parameter +of type const char* implicitly (by default). Such assignments +should be used carefully, since the library does not keep track of whether a char +pointer refers to the given string buffer. To make sure that a char pointer refers +to a valid string buffer, always make the scope of a char pointer variable smaller +than or equal to the scope of a string object. In most cases passing a string +object to a system or API call is safe (see examples below). This typecast operator +does not perform any actions and simply returns a pointer to the string buffer.

+

The value of the char pointer is guaranteed to be non-NULL. Even if the string +is empty, the char pointer will refer to a null-symbol.

+

A string buffer can not be modified through a constant char pointer. If you +want to modify the string buffer through a char pointer, use unique(string&) +function instead. This function always returns a reference to a unique string +buffer (i.e. when the reference count is 1).

+

Compatibility note: MSVC and GCC may treat type casts in different ways +when passing a string object to a function that takes (...) parameters, e.g. printf() +or outstm::putf(). You should explicitly instruct the +compiler to cast the string object to (const char*) +to avoid this problem. PTypes provides a shorter typedef pconst +for this.

+

Examples

+
+
+void assignment_example()
+{
+   string s = "abcdef";
+   const char* p = s;
+   // do string manipulation here...
+}
+
+void function_call_example()
+{
+   string s = "abcdef";
+   puts(s);
+   printf("%s\n", pconst(s));
+}
+
+
+

See also: Constructors/destructors, +Operators, Manipulation, +Conversion

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/styles.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/styles.css Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,16 @@ +p {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px} +td {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px} +h5 {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px} +a:link { } +a:visited {color: #0066CC} +a:hover {color: #FF0033; text-decoration: underline} +a:active {color: #FF0033} +.seealso {font-weight: bold; background-color: #dddddd; padding-left: 10px; padding-right: 10px; padding-top: 3px; padding-bottom: 4px} +.lang {color: #557799; font-weight: bold } +.def {color: #557799; font-weight: bold } +.hpath {font-size: 16px; font-weight: bold; padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; font-family: Arial, Helvetica, sans-serif; font-style: italic} +.comment { color: #009900; font-weight: normal;} +.menu {font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px ; font-weight: bold} +.ns { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px} +li { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px } +.cdir { color: #0000FF; font-weight: normal; } diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/time.calendar.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/time.calendar.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,70 @@ + + + +PTypes: date/time: calendar + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +Date/time: Date/calendar manipulation

+
+
#include <ptime.h>
+
+typedef large datetime;
+
+bool     isleapyear(int year);
+int      daysinmonth(int year, int month);
+int      daysinyear(int year, int month);
+int      dayofweek(datetime d);
+bool     isdatevalid(int year, int month, int day);
+datetime encodedate(int year, int month, int day);
+bool     decodedate(datetime d, int& year, int& month, int& day);
+
+
+

bool isleapyear(int year) determines whether year +is a leap year.

+

int daysinmonth(int year, int month) returns the +number of days in month (1 - 12). The parameter year +is needed to determine whether it's a leap year in order to return the correct +number of days for February. The returned value can be in the range 28 - 31. If +month is out of the allowed range (1 - 12) this function +returns 0.

+

int daysinyear(int year, int month) returns the number +of days since the beginning of the year up to the month +(1 - 12), inclusive. If month is 12 the function will +return the total number of days in the year. If month +is out of the allowed range (1 - 12) this function returns 0.

+

int dayofweek(datetime d) returns the day of the +week (0 - 6) for the given date d. 0 corresponds to +Sunday, 1 - Monday etc. This function does not check the value of d +for validity, it always returns some result in the range 0 - 6.

+

bool isdatevalid(int year, int month, int day) checks +the values of year, month +and day for validity. This function takes into account +that day must be in the correct range depending on year +and month. Also, it checks whether year +is in the allowed range 1 - 9999.

+

datetime encodedate(int year, int month, int day) +returns a datetime value, i.e. the number of milliseconds +since the beginning of the calendar up to the midnight of month/day/year. +This value can then be added to the value returned by encodetime() +to form the exact time stamp with millisecond precision, or it can be used alone +as a calendar date value without the time correction.

+

bool decodedate(datetime d, int& year, int& month, int& +day) is the inverse version of encodedate(): +it breaks the value of d into its year, +month and day. This function +returns false if the value of d +is invalid.

+

See also: Datetime type, Time +manipulation

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/time.datetime.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/time.datetime.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,92 @@ + + + +PTypes: date/time: datetime + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +Date/time: Datetime type

+
+
#include <ptime.h>
+
+typedef large datetime;
+
+datetime  now(bool utc = true);
+int       days(datetime d);
+int       msecs(datetime d);
+datetime  mkdt(int days, int msecs);
+bool      isvalid(datetime d);
+void      tzupdate();
+int       tzoffset();
+string    dttostring(datetime d, const char* fmt);
+string    nowstring(const char* fmt, bool utc = true);
+datetime  utodatetime(time_t u);
+
+

datetime now(bool utc = true) returns the current +date/time. The returned value can be either the local time or the Universal Coordinated +Time (UTC, aka GMT), depending on the parameter utc. +It is recommended to manipulate with the UTC time internally in your application +whenever possible (f.ex. when it's not needed to display the time to the user), +since in many countries the local time may be automatically adjusted when entering +or leaving the daylight saving period, which may confuse your application. On +the contrary, the UTC time never changes. That's why all modern operating systems +rely on the UTC time internally. (See also tzupdate() +below for additional notes).

+

int days(datetime d) returns the number of days since +the beginning of the calendar contained in the datetime +value d.

+

int msecs(datetime d) returns the number of milliseconds +since midnight contained in the datetime value d.

+

datetime mkdt(int days, int msecs) calculates the +datetime value from days and msecs +parameters. Days is the number of days since the beginning +of the calendar, and msecs is the number of milliseconds +since midnight. No checks are made for validity of these values. There exists +an easier way to build a datetime value using encodedate() +and encodetime() functions having the year, month and +day numbers, as well as (not necessarily) the hour, minute, second and millisecond +values.

+

bool isvalid(datetime d) checks a datetime +value for validity. The value of d is valid if it holds +a time stamp between 01/01/0001 and 12/31/9999.

+

void tzupdate() updates the internal timezone information, +which affects the value of local time returned by now() +and nowstring(). If your application is supposed to +be running infinitely (e.g. if it's a network daemon), you might want to update +the internal timezone information from time to time in order to return correct +local time to the user on DST adjustment days. Depending on the precision of local +time you wish to show to the user, you can call this function, for example, every +minute or every hour. Without this, the local time may become incorrect at the +moment of DST adjustment, which occurs twice a year in most countries.

+

int tzoffset() returns the time zone offset in minutes. +This value is negative in the West. Multiplying this value by 60000 (i.e. the +offset in milliseconds) and adding it to the UTC datetime +value will give the local time.

+

string dttostring(datetime d, const char* fmt) converts +a datetime value to string representation as specified +by fmt. The syntax of the format specifier is the same +as for strftime() (please, refer to the corresponding +manual pages in your programming environment). Note that there might be slight +incompatibilities between different implementations of strftime(). +

+

string nowstring(const char* fmt, bool utc = true) +returns a string representing the current time in a format specified by fmt. +Utc specifies whether the local time or the UTC time +is required. Like for dttostring(), the syntax of the +format specifier fmt is the same as for the system function +strftime().

+

datetime utodatetime(time_t u) converts UNIX time_t +value to PTypes datetime.

+

See also: Date/calendar manipulation, +Time manipulation

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/time.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/time.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,80 @@ + + + +PTypes: date/time: + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +Date/time:

+ +

The datetime data type and the accompanying utilities +provide portable (system-independent) means of calendar and time manipulation. +Datetime is equivalent to signed 64-bit integer type +(large type in PTypes) which holds a time value with +a millisecond precision in the range of dates 01/01/0001 through 12/31/9999. The +value of a datetime variable represents the number of milliseconds since the beginning +of the calendar, i.e. midnight January 1st, year 1. The upper limit is caused +by the fact that the leap year rule may (and most likely will) change after the +year 10000.

+

Variables of type datetime can be used in various +ways: as a date/time stamp, as a difference between two events in the range from +1 millisecond up to 10,000 years, as a date alone without the time (e.g. for calendar +manipulation), and as a time value alone.

+

The date/time manipulation functions are divided into 3 groups in this documentation: +general, date/calendar +and time. Most of these functions work with parameters +of type datetime. The prototypes and other declarations +are in the header file <ptime.h>.

+

Here are some examples of using datetime and the +accompanying utilities:

+
+
#include <pasync.h>    // for psleep()
+#include <ptime.h>
+#include <pstreams.h>
+
+USING_PTYPES
+
+int main()
+{
+    // PTypes' birthday (birth moment, if you wish)
+    datetime d = encodedate(2000, 3, 30) + encodetime(13, 24, 58, 995);
+    // The format specifier %t is for timestamps
+    pout.putf("PTypes' birth moment: %t\n", d);
+    
+    // now see how old is PTypes in milliseconds
+    datetime diff = now() - d;
+    int hours, mins, secs, msecs;
+    decodetime(diff, hours, mins, secs, msecs);
+    pout.putf("PTypes' life time: %d hours %d minutes %d seconds and %d milliseconds\n",
+        days(diff) * 24 + hours, mins, secs, msecs);
+    
+    // measure the difference in milliseconds between two calls to now()
+    datetime m = now();
+    psleep(17);  // sleep 17 milliseconds
+    pout.putf("A 17 millisecond dream lasted actually %d milliseconds\n", now() - m);
+    // this will show the actual precision of the clock on the given platform;
+    // Windows, f.ex., always shows the difference in 10 msec increments
+}
+
+
+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/time.time.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/time.time.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,45 @@ + + + +PTypes: date/time: time + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +Date/time: Time manipulation

+
+
#include <ptime.h>
+
+typedef large datetime;
+
+bool     istimevalid(int hour, int min, int sec, int msec = 0);
+datetime encodetime(int hour, int min, int sec, int msec = 0);
+bool     decodetime(datetime d, int& hour, int& min, int& sec [, int& msec] );
+
+
+

bool istimevalid(int hour, int min, int sec, int msec = +0) checks whether hour, min, +sec and msec (millisecond) +contain correct values in their respective ranges. The last parameter is optional.

+

datetime encodetime(int hour, int min, int sec, int msec += 0) returns a datetime value, i.e. the number +of milliseconds since midnight. This function does NOT check the input parameters +for validity. The value returned by this function can be added to the return value +of encodedate() to form the exact time stamp for the +given year, month, day, hour, minute, second and (optionally) millisecond.

+

bool decodetime(datetime d, int& hour, int& min, int& sec +[, int& msec] ) splits the value of d into hour, +minute, sec and msec +(millisecond) passed since midnight. The last parameter is optional.

+

See also: Datetime type, Date/calendar +manipulation

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/title-21.png Binary file doc/title-21.png has changed diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/unit.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/unit.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,136 @@ + + + +PTypes: unit + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +unit

+

+

+
#include <pstreams.h>
+
+class unit {
+    compref<instm> uin;
+    compref<outstm> uout;
+
+    virtual void main() = 0;
+    virtual void cleanup() = 0;
+
+    void connect(unit* next);
+    void run(bool async = false);
+    void waitfor();
+}
+
+

Units represent functionality similar to console +applications in UNIX. Each unit has its own main() along +with input and output 'plugs' - uin and uout, +that may be mapped to the standard input and output, a local pipe or any other +stream compatible with instm and outstm, +respectively.

+

Each unit class must at least override the abstract method main(). +Overridden unit classes typically read input data from uin +and send the result of processing to uout, like if they +were console applications. By default uin and uout +are attached to standard input and output. After instantiating a unit object you +(the user of a unit class) may attach any instm-compatible +stream to uin and any outstm-compatible +stream to uout. In addition, units are able to connect +to each other using local pipes, and thus form data processing chains within your +application.

+

You may define other public methods or fields in your unit class that represent +additional options. E.g. a regular expression parser unit may have a string field +that represents the regular expression itself (see example below).

+

Units can be run either synchronously or asynchronously. In the latter case, +a separate thread is created for executing unit's main() +function. If connected to a pipe using connect(), the +first unit in the chain runs within the scope of the calling thread, the others +run in separate threads.

+

The unit class is a subclass of component, +and thus it inherits reference counting and delete notification mechanisms from +component. Unit is declared +in <pstreams.h>.

+

This interface is available only in the multithreaded versions of the library. +

+

compref<instm> unit::uin is a reference-counted +pointer to an input stream, that is unit's input 'plug'. By default uin +refers to the standard input object pin. Typically both +uin and uout are assigned +by the user of the unit after instantiating a unit object. You may assign dynamically +allocated stream objects to uin and uout +- they will be freed automatically by the 'smart' compref +pointer.

+

compref<outstm> unit::uout -- same as uin; +represents the output 'plug' of the unit.

+

virtual void unit::main() is unit's main code. Override +this method to implement functionality of your mini-process. Note that code in +main() must avoid accessing static/global data, since +it may be executed in a separate thread. You may choose to write a reusable unit, +i.e. when main() can be called multiple times for the +same object, however main() is protected from overlapping +(recursive) calls, which means, you need not to write reentrant code in this function.

+

virtual void unit::cleanup() -- override this method +to perform finalization and cleanup of a unit. This function is guaranteed to +be called even if main() threw an exception of type +(exception*) or a derivative.

+

void unit::connect(unit* next) connects a unit object +to another object using a local pipe. Multiple units can be connected to form +a chain. A user then calls run() for the first object; +all other members of the chain are started automatically in separate threads.

+

void unit::run(bool async = false) runs a unit object. +This function calls main() for the given object and +possibly for other units, if this is the first object of a chain. You can not +call run() for an object which is not the first in a +chain. If async is true, this +function starts a unit in a separate thread and returns immediately. Use waitfor() +to synchronize with the completion of a unit if started asynchronously.

+

void unit::waitfor() waits for the unit to terminate +if run asynchronously. For unit chains, this method needs to be called only for +the first object in a chain.

+

Example. Consider there is a unit type ugrep +that performs regular expression matching and a unit type utextconv +for converting various text formats. The code below demonstrates how to connect +these units and run the chain.

+
+
#include <pstreams.h>
+
+#include "ugrep.h"        // imaginary headers with unit declarations
+#include "utextconv.h"
+
+USING_PTYPES
+
+int main()
+{
+    ugrep grep;
+    grep.regex = "^abc";
+    grep.casesens = false;
+
+    utextconv textconv;
+    textconv.from = CONV_UNIX;
+    textconv.to = CONV_WIN;
+
+    // connect the two units and set up the input and output plugs.
+    grep.uin = new ipstream("somehost.com", 8282);
+    grep.connect(&textconv);
+    textconv.uout = new outfile("output.txt");
+
+    // now run the chain; will read input from the socket, pass 
+    // through the grep and textconv units and write it to the 
+    // output file.
+    grep.run();
+}
+
+
+

See also: unknown & component, +Streams

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/unknown.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/unknown.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,107 @@ + + + +PTypes: unknown & component + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +unknown & component

+

+

+
#include <ptypes.h>
+
+class unknown {
+    unknown();
+    virtual ~unknown();
+}
+
+class component {
+    component();
+    virtual ~component();
+    void addnotification(component* c);
+    void delnotification(component* c);
+    virtual void freenotify(component* c);
+}
+
+component* addref(component*);
+bool release(component*);
+
+template <class T> class compref;
+
+int objalloc;
+
+

The unknown interface is the base for all interfaces +(classes) in PTypes, except string, cset, +variant, mutex, rwlock, +msgqueue and tpodlist. The +unknown class has no semantic or functional meaning, +except that deriving a class from unknown provides a +simple mechanism of tracking the number of created/destroyed objects in a program. +Historically, unknown was used in PTypes as a base for +all list item types, however, starting from version 2.0 of the library this requirement +is no longer in place.

+

The component class adds reference-counting functionality +to unknown (see addref() and +release() below). PTypes variants require objects to +be derived from component instead of unknown +to be able to make assignments and destruction of variants properly. See also +compref below.

+

As an alternative to reference-counting component +also provides so-called 'delete notification' mechanism. If object A holds a reference +to object B, A can add itself to B's notification list to be notified when B is +being destroyed. This allows A to take appropriate actions, e.g. invalidate the +reference to B. A in this case can declare reference to B as a plain pointer. +In other words, A should override its own virtual method freenotify(), +and it also should call addnotification(this) for the +object it holds reference to.

+

All stream objects in PTypes and aslo the unit class +are derived from component.

+

A global variable objalloc is declared to keep track +of the number of allocated objects (derived from unknown +or component) in an application program, which can help +you to find memory leaks or other potential bugs. The allocation counting works +only in DEBUG mode. If the memory is cleaned up properly, +this value should be zero upon program termination. You can write code, possibly +enclosed within #ifdef DEBUG ... #endif, which checks +whether this value is zero at the end of main().

+

These interfaces are declared in <ptypes.h>.

+

component* addref(component* c) increments the reference +counter for the given component object c. The return +value is the same as c and is provided for convenience.

+

bool release(component* c) decrements the reference +counter and destroys the object c if the counter reached +0. Returns true if the object has been destroyed. Passing +NULL to this function is not an error.

+

template <class T> class compref implements +a 'smart' pointer to component (or any derivative class) +with automatic reference counting. Use this template in place of a plain pointer +declaration (e.g. compref<myclass> instead of +myclass*) to automatically destroy objects as soon as +there are no more references left. The behavior of compref +pointers is similar to plain pointers, except that they perform additional actions +when assigning new values to them.

+

virtual component::~component() destroys the component +and calls freenotify() for each object in the notification +list.

+

component::addnotification(component* c) adds object +c to the notification list of this object. This object's +destructor will then call c->freenotify().

+

component::delnotification(component* c) deletes object +c from this object's notification list.

+

virtual component::freenotify(component* caller) is +called by the caller's destructor for each object +in the notification list. This method should be overriden in classes which add +themselves to other objects' notification lists. The overridden method usually +invalidates (assigns NULL) all references to caller.

+

See also: Lists, variant

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/variant.arrays.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/variant.arrays.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,86 @@ + + + +PTypes: variant: arrays + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +variant: Arrays

+
+
+#include <ptypes.h>
+ 
+void aclear(variant& a);
variant aclone(const variant& a); + +void put(variant& a, <key>, const variant& item); +const variant& get(const variant& a, <key>); +const variant& variant::operator [](<key>) const; +void del(variant& a, <key>); + +bool anext(const variant& array, int& index, variant& item, [ string& key ]); +
+
+

A variant object can hold an associative array of variants. The variant changes +its type to an array as soon as put() or aclear() +is called for an object. When assigning variants, only a reference to an array +is being copied, which means, modifying an array through one variant object affects +all other objects that hold a reference to the same array. To duplicate the contents +of an array use aclone().

+

Variant arrays can associate values with either strings or integers (32 or +64 bit). Integer keys are not required to be consecutive. It should be noted that +in the current implementation there is no difference in performance between these +two methods. Both methods can be mixed in one array.

+

PTypes uses reference counting on arrays to properly clean up unused dynamic +structures. However, since variant arrays may recursively contain arrays and in +some situations there may be a circular reference, it is possible to have memory +leak when using such structures. Since PTypes does not provide garbage collection +(e.g. like in Java), compound variant data structures should be designed so that +variants never reference each other circularly.

+

void aclear(variant& a) clears the variant array. +This function may affect other variant objects holding a reference to the same +array data.

+

variant aclone(const variant& a) creates a copy +of an array or creates an empty array if a is of any +other variant type. If a contains variant arrays as +elements, only their references are copied.

+

void put(variant& a, <key>, const variant& +item) associates item with key +in the variant array a. Key +can be either a string or an integer. The previous value associated with this +key, if any, is replaced with the new value. If item +is an unassigned variant, the new value is not stored in the array.

+

const variant& get(const variant& a, <key>) +retrieves an element associated with key in the array +a. If the element does not exist, or a +is not an array, this function returns an unassigned variant (a reference to nullvar). +Key can be either a string or an integer. Variant arrays +use hashing to retrieve elements by keys.

+

const variant& variant::operator [](<key>) +equivalent to get(). This operator can be used only +for retrieving elements.

+

void del(variant& a, <key>) removes +the element associated with key from the array a. +Does nothing if the element does not exist or a is not +an array. Equivalent to calling put() with an unassigned +variant item.

+

bool anext(const variant& a, int& index, variant& +item, [ string& key ]) iterates through array elements (please see +examples in the introduction to variants). Each time anext() +is called it assigns the next item in the array to item +and optionally assigns its key value to key. Index +must be zero when calling this function first time. If there are no items left +in the array, or a is not an array, this function returns +false.

+

See also: string, Assignments +and typecasts, Object references, Utilities

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/variant.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/variant.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,79 @@ + + + +PTypes: variant + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +variant

+ +

The variant class offers a universal and flexible +way to store values whose types can not be determined at compile time. A variant +object can hold integer, boolean, floating point or string values as well as associative +arrays of variants or references to objects derived from component. +Variants can change their types at run-time. In return for their flexibility, +variants have some memory usage and performance overhead. They always occupy 12 +bytes of static or local memory, however, they may also use dynamic memory allocation +for strings and arrays.

+

The variant class provides all possible automatic +typecasts, so that in most cases, when variants are used in assignments and function +calls, the compiler will generate implicit typecasts appropriate for the context. +The typecast functions always try to perform conversion regardless of the current +and target types, although it may not always be sensible. For example, if a variant +object holds an integer value, an attempt to cast it to a string will result in +converting the value to its string representation; if a variant is an associative +array, an attempt to cast it to boolean will return true if the array is not empty. +Variant typecast routines never generate errors except when a 64-bit integer value +is converted to 32-bit int and the value exceeds the allowed range.

+

A variant variable may itself represent an associative array of variants.

+

This interface can be useful for (but not limited to) designing interpreters +and compilers, working with databases and spreadsheets, etc.

+

The variant class is declared in <ptypes.h>.

+

Examples

+
+
variant v1 = 11;
+variant v2 = "33";
+variant v3 = int(v1) + int(v2) + 22;  // explicit typecasts: without them the compiler can't 
+variant v4 = string(v2) + " cows";    //    figure out which of + operators to use here
+large i1 = v1;                        // implicit typecast is possible here
+int a = v2;                           // large-to-int: may generate (evariant*) exception
+variant v5;
+put(v5, "key1", v1);                  // variants may be associated with both strings and
+put(v5, 15, "value2");                //    integer values in variant arrays
+variant v6 = v5[15];
+variant v7 = v5;                      // a reference to the array is passed
+
+variant varray = aclone(v5);          // array is duplicated
+
+variant item;                         // array iteration example
+for (int i = 0; anext(varray, i, item); )
+    pout.putf("%d: %d\n", i, int(item));
+
+

See also: string, unknown +& component, Assignments and typecasts, +Arrays, Object +references, Utilities

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/variant.objrefs.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/variant.objrefs.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,39 @@ + + + +PTypes: variant: object references + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +variant: Object references

+


+Variants can hold references to objects derived from component. +PTypes performs reference counting, so that assigning variants containing object +references can be considered safe: an object will only be destroyed when there +are no more references left to it. If you want to control the destruction of an +object 'manually', you can increment the reference count with addref() +before assigning a reference to a variant (see unknown +& component). In this case, each call to addref() +should be balanced with a call to release().

+

It should be noted that the reference counting mechanism has a potential flaw +which may lead to memory leaks. Consider two objects containing variants with +cross-referencing pointers to each other. The library can not keep track of such +circular references, and an attempt to free one of the objects will result in +destroying only one of them and leaving the other in the memory without any references +to it. This is a known problem and can be solved by either eliminating circular +references when designing data structures or by providing a complex memory 'garbage +collector' which keeps track of all object references in the program.

+

See also: unknown & component, +Assignments and typecasts, Arrays, +Utilities

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/variant.typecasts.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/variant.typecasts.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,75 @@ + + + +PTypes: variant: assignments and typecasts + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +variant: Assignments and typecasts

+


+Variants may hold values of the following types:

+ +

Variants are compatible with variables and constants of all numeric types, +the string type and a pointer to component, which means, +you can assign any of these values to a variant object and vice versa, including +passing as parameters to functions. The type of a variant can be changed at run-time +by simply assigning a new value to it.

+

By default variants are initialized to an unassigned state, which is the same +as calling clear() for a variant object.

+

You may store datetime values in variants, since +datetime is equivalent to large +in PTypes. Besides, arbitrary binary data can be stored in a dynamic string and +then assigned to a variant.

+

The variant class declares (or rather, overloads) all possible typecast operators +to other fundamental data types. These typecast operators always try to return +some value, even when it is not sensible. Below is a list of rules for typecasts +that may make sense in your program, leaving the other less meaningful cases as +'unspecified'. Although variants store integers as 64-bit values, for simplicity +we use the word int in this list.

+ +

Typecast operators never affect the actual value of a variant object.

+

When trying to cast a variant to signed or unsigned 32-bit int, +the typecast operator first casts the value to 64-bit large +according to the rules above, and then checks the resulting value. If the value +is out of range, an exception of type (evariant*) is raised. You may always cast +variants to large to get rid of extra exception handling +code in your program.

+

See also: string, datetime, +unknown & component, Arrays, +Object references, Utilities

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/variant.utils.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/variant.utils.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,49 @@ + + + +PTypes: variant: utilities + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: Basic types: +variant: Utilities

+
+
#include <ptypes.h>
+ 
+enum { VAR_NULL, VAR_INT, VAR_BOOL, VAR_FLOAT,
+       VAR_STRING, VAR_ARRAY, VAR_OBJECT };
+ 
+void clear(variant&);
+int  vartype(const variant&);
+
+bool isnull(const variant&);
+bool isint(const variant&);
+bool isbool(const variant&);
+bool isfloat(const variant&);
+bool isstring(const variant&);
+bool isarray(const variant&);
+bool isobject(const variant&);
+
+const variant nullvar;
+
+
+

void clear(variant&) clears the variant and sets +its state to unassigned (null).

+

int vartype(const variant&) returns the type of +a variant, which can be compared with one of the VAR_XXX +constants.

+

bool isXXX(const variant&) this group of inlined +functions is provided to check whether the variant is of particular type.

+

See also: Assignments and +typecasts, Arrays, Object +references

+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 doc/wshare.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/wshare.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,149 @@ + + + +PTypes: wshare + + + + + +

C++ Portable Types Library (PTypes) Version 2.1 +


+ +

Top: PTypes demo program -- wshare

+


+Overview

+
+

Wshare is a simple multithreaded web server (HTTP +daemon) that uses almost all functional parts of the library and serves as an +example of using PTypes. Wshare supports protocol versions +up to HTTP/1.1. It provides simple means of sharing files over the web, but it +lacks server-side scripting and authentication functionality.

+
+

The program is covered by the same license as PTypes. The authors can not +be responsible for any data loss or accidental disclosure of confidential information +caused by this software. It is provided `as is' with the hope that it can be useful +both as a library demo program and a simple web server.

+
+

The sources are in ./wshare. On UNIX, this application +is built along with the library and is copied to ./bin. +For MSVC, a separate project is provided as a part of the PTypes workspace. For +BCC on Windows, the makefile is wshare/wshare.mak.

+

Wshare does not require any special installation +or configuration procedures and can be easily run from the command line with at +least one parameter: the directory you wish to share over the web. Note that wshare +does not understand .htaccess or any other configuration +files in your directories, so the web site you might previously have will run +with wshare's default configuration and access rights.

+

Wshare is scalable: you can write your own handlers +for new HTTP methods, virtual paths and for specific file extensions. Currently +custom modules can be incorporated into wshare only +at compile-time. Please, see wshare/modules.h and wshare/request.h +for details. Also take a look at the sample compile-time module wshare/mod_about.cxx.

+

Please, run the program to see the summary of the command-line options.

+
+
+usage: wshare [options] document-root
+
+  -D              daemonize, UNIX only
+  -d              allow directory indexes
+  -g group        group ID to run as, UNIX only
+  -n num          maximum number of simultaneous connections (default: 30)
+  -o file-name    write HTTP access log to file-name
+  -p port-num     port number to listen to
+  -u user         user ID to run as, UNIX only
+  -x              always show directory indexes (ignore default index files)
+
+
+
+


+Running on UNIX

+
+

By default the daemon is trying to bind to port 80, which is a privileged port +on UNIX. You will have to either run it as root, or to specify a port number higher +than 1024 with the option -p port-number, +e.g. -p 8080.

+

Wshare uses UNIX's syslog to log error messages. +The HTTP access log goes to stderr, which can be overridden with -o logfile.

+

Wshare can also daemonize itself, i.e. detach from +the console and remain active after the user logs out. Use option -D +to daemonize the program. After that, the only way to stop the server is to send +a SIGKILL signal, i.e. determine the process ID with ps +and then invoke kill -KILL PID. On +some systems you will need to use ps with the option +that specifies your user ID.

+

For better security, wshare can downgrade process +privileges to the user/group specified through -u user +and -g group command-line options. This is done +after binding to the socket and opening the log file. If -g +is omitted and only -u is specified, wshare +downgrades the process to the primary group of that user. For example, if you +specify -u nobody, the group will be automatically assigned +to a group nobody.

+
+


+Running on Windows

+
+

On Windows wshare runs as a simple console application. +All you can do with wshare on Windows is to specify +a different port to bind to with option -p port-number +and to redirect the HTTP access log to some file with option -o logfile. +Redirecting the access log to a file instead of writing it to the console window +can speed up the server.

+
+


+Common features

+
+

By default wshare does not generate directory indexes +(analogue of `Option Indexes' in Apache's configuration), which means the directory +must have a default index file named as either of: index.html, +Index.html or default.htm. +Directory indexes can be allowed by specifying option -d. +In this case, if the directory does not have any of the default index files listed +above, wshare will generate a page with the list of +files the directory contains.

+

If you don't want default index files at all, use option -x +in the command line: the server will then show the directory indexes, like if +you specified an empty "DirectoryIndex" directive with Apache.

+

You can limit the number of simultaneous connections with option -n +num, which is 30 by default. When the number of connections reaches +num/2 , the server stops supporting persistent connections. +When it reaches num, the server sends "503 Service +unavailable" to the client. And finally, when the number of connection requests +reaches num * 2, wshare simply aborts the connection +by closing the socket.

+

You can get the current status of the server by requesting http://localhost/.wstat +in your browser. Wshare responds to this request only +if the client is on the same host as the server, i.e. localhost +or 127.0.0.1.

+

Some other features are hardcoded into wshare and +can be changed only by recompiling it. The list of default index files can be +found in wshare/config.cxx, and the file extension-to-MIME +translation table is in wshare/mimetable.cxx. An awk +script wshare/mimetable.awk is provided to translate +an apache-style mime.conf file into C++ code that can +be linked with wshare.

+
+


+Examples (UNIX)

+
+

The simplest usage:

+
+

wshare ./

+
+

Quickly share your files through port 8080 and ignore any index.html files +in the directories:

+
+

wshare -x -p 8080 ~/mydocs

+
+

Run a real server for real users (must be root on UNIX):

+
+

wshare -D -n 100 -u nobody -o /var/log/wshare-access.log /usr/local/www

+
+

BE CAREFUL and double check the directory you are opening to the world.

+
+ +
+PTypes home + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 include/pasync.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/pasync.h Wed May 08 23:49:28 2013 -0500 @@ -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 -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 include/pinet.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/pinet.h Wed May 08 23:49:28 2013 -0500 @@ -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 -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 include/pport.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/pport.h Wed May 08 23:49:28 2013 -0500 @@ -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 -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 include/pstreams.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/pstreams.h Wed May 08 23:49:28 2013 -0500 @@ -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 -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 include/ptime.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/ptime.h Wed May 08 23:49:28 2013 -0500 @@ -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 -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 include/ptypes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/ptypes.h Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,1156 @@ +/* + * + * 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 ptpublic _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 + + static void idxerror(); + + _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 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; } + + 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& a, int&, 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(); +}; + + + +// -------------------------------------------------------------------- // +// --- 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 -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 index.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/index.html Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,80 @@ + + +C++ Portable Types Library (PTypes) Version 2.1 + + + + +C++ Portable Types Library (PTypes) Version 2.1 +
+
+

The purpose of software engineering 
+is to manage complexity, not to create it.
+Bill Catambay

+
+

PTypes (C++ Portable Types Library) is a simple alternative to the +STL that includes multithreading and networking. It defines dynamic strings, variants, +character sets, lists and other basic data types along with portable thread and +synchronization objects, IP sockets and named pipes. Its main `target audience' +is developers of complex network daemons, robots or non-visual client/server applications +of any kind.

+

PTypes defines simple and intuitive interfaces and differs from the STL in +fairly moderate use of templates. The library is portable across many modern operating +systems (currently Linux, MacOS X, SunOS, FreeBSD, HP-UX and Windows). All platform-dependent +issues are hidden inside. A simple web server called wshare is included in the +package to demonstrate the full power of the library.

+

And finally, PTypes is open and free.

+
    +
  • +

    Documentation
    +The documentation is available both on-line and off-line, i.e. as a part of the +downloadable package. You may want to take a look at the Introduction +first.

    +
  • +
+
    +
  • +

    License
    +PTypes is a free library and is covered by a simple license known as "zlib/libpng +License". It grants full freedom to use the library for commercial, educational +or any other purpose except that you can not change its name and/or the copyright +notice and redistribute it as your own work.

    +
  • +
+ +
    +
  • +

    Subscribe to new releases
    +Become a freshmeat.net user and subscribe to the future announcements about PTypes. +(freshmeat itself is a huge repository of open-source software.)

    +
  • +
+ +

The original location of this library is http://www.melikyan.com/ptypes/

+ + + + + + + +

© 2001-2007 Hovik Melikyan
+ + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/Makefile.Darwin --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Makefile.Darwin Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,29 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for MacOS X (Darwin), called from ../Makefile +# + +CXX = c++ + +OS_CXXOPTS_ST = -Wall -Wno-long-double -fno-common +OS_CXXOPTS = $(OS_CXXOPTS_ST) -fPIC + +LIBTOOL = $(CXX) -dynamiclib +SOSTRIP = test + +SOEXT = dylib +SOINSTOPT = -install_name /usr/lib/$(SOREALNAME) + +PREFIX = /usr + +include Makefile.common + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/Makefile.FreeBSD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Makefile.FreeBSD Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,31 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for FreeBSD, called from ../Makefile +# + +CXX = g++ + +OS_CXXOPTS_ST = -Wall +OS_CXXOPTS = $(OS_CXXOPTS_ST) -pthread -fPIC + +# OS_LDLIBS = -lc_r + +LIBTOOL = $(CXX) -shared -pthread +SOSTRIP = strip + +SOEXT = so +SOINSTOPT = -h $(SOREALNAME) + +PREFIX = /usr/local + +include Makefile.common + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/Makefile.HP-UX --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Makefile.HP-UX Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,32 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for HP-UX, called from ../Makefile +# + +CXX = aCC + +OS_CXXOPTS_ST = -z -ext -D_HPUX_SOURCE -D_FILE_OFFSET_BITS=64 +OS_CXXOPTS = $(OS_CXXOPTS_ST) -mt +z + +# OS_LDLIBS_ST +OS_LDLIBS = -lrt + +LIBTOOL = $(CXX) -b -mt +SOSTRIP = strip + +SOEXT = sl +SOINSTOPT = -Wl,+h,$(SOREALNAME) + +PREFIX = /usr/local + +include Makefile.common + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/Makefile.Linux --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Makefile.Linux Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,29 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for Linux, called from ../Makefile +# + +CXX = g++ + +OS_CXXOPTS_ST = -Wall -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 +OS_CXXOPTS = $(OS_CXXOPTS_ST) -pthread -fPIC + +LIBTOOL = $(CXX) -shared -pthread +SOSTRIP = strip + +SOEXT = so +SOINSTOPT = -Xlinker -soname -Xlinker $(SOREALNAME) + +PREFIX = /usr + +include Makefile.common + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/Makefile.SunOS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Makefile.SunOS Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,40 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for SunOS, called from ../Makefile +# + +CXX = g++ +AS = as + +OS_CXXOPTS_ST = -Wall -D_FILE_OFFSET_BITS=64 +OS_CXXOPTS = $(OS_CXXOPTS_ST) -D_REENTRANT -fPIC + +OS_LDLIBS_ST = -lsocket -lnsl -lposix4 +OS_LDLIBS = $(OS_LDLIBS_ST) -lpthread + +LIBTOOL = $(CXX) -shared +SOSTRIP = strip + +SOEXT = so +SOINSTOPT = -h $(SOREALNAME) + +PREFIX = /usr/local + +EXTRA_OBJS = mt/patomic.sparc.o +ASOPTS = -xarch=v8plus + +mt/patomic.sparc.o: patomic.sparc.s + $(AS) $(ASOPTS) -o $@ patomic.sparc.s + + +include Makefile.common + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/Makefile.common --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Makefile.common Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,463 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for all platforms, called automatically from +# Makefile. +# + +.SUFFIXES: .cxx .o + +AR = ar cru +RANLIB = ranlib + +DDEBUG = -DDEBUG +INCDIR = ../include +CXXOPTS = $(OS_CXXOPTS) $(DDEBUG) -I$(INCDIR) -O2 +LDLIBS = $(OS_LDLIBS) + +CXXOPTS_ST = -DPTYPES_ST $(OS_CXXOPTS_ST) $(DDEBUG) -I$(INCDIR) -O2 +LDLIBS_ST = $(OS_LDLIBS_ST) + +LIBNAME = libptypes.a +LIBNAME_ST = libptypesn.a +LIBDEST = ../lib + +SOBASENAME = libptypes +SONAME = $(SOBASENAME).$(SOEXT) +SOVER = 21 +SOREALNAME = $(SOBASENAME).$(SOEXT).$(SOVER) +SODEST = ../so + + +LIBOBJS = mt/pversion.o mt/pmem.o mt/pfatal.o mt/pstring.o mt/pcset.o mt/pcsetdbg.o \ + mt/pstrmanip.o mt/pstrutils.o mt/pstrconv.o mt/pstrtoi.o mt/pstrcase.o mt/ptime.o \ + mt/punknown.o mt/pcomponent.o mt/pexcept.o mt/ppodlist.o mt/pobjlist.o mt/pstrlist.o mt/ptextmap.o \ + mt/patomic.o mt/pasync.o mt/psemaphore.o mt/pthread.o mt/pmsgq.o mt/ptimedsem.o \ + mt/prwlock.o mt/ptrigger.o mt/pmtxtable.o mt/pvariant.o \ + mt/piobase.o mt/pinstm.o mt/pinfile.o mt/ppipe.o mt/pinmem.o mt/poutmem.o \ + mt/pintee.o mt/poutstm.o mt/poutfile.o mt/pinfilter.o mt/poutfilter.o mt/pmd5.o \ + mt/pputf.o mt/pstdio.o mt/pfdxstm.o mt/pnpipe.o mt/pnpserver.o \ + mt/pipbase.o mt/pipsvbase.o mt/pipstm.o mt/pipstmsv.o mt/pipmsg.o mt/pipmsgsv.o \ + mt/punit.o \ + $(EXTRA_OBJS) + +LIBOBJS_ST = st/pversion.o st/pmem.o st/pfatal.o st/pstring.o st/pcset.o st/pcsetdbg.o \ + st/pstrmanip.o st/pstrutils.o st/pstrconv.o st/pstrtoi.o st/pstrcase.o st/ptime.o \ + st/punknown.o st/pcomponent.o st/pexcept.o st/ppodlist.o st/pobjlist.o st/pstrlist.o st/ptextmap.o \ + st/patomic.o st/pvariant.o \ + st/piobase.o st/pinstm.o st/pinfile.o st/ppipe.o st/pinmem.o st/poutmem.o \ + st/pintee.o st/poutstm.o st/poutfile.o st/pinfilter.o st/poutfilter.o st/pmd5.o \ + st/pputf.o st/pstdio.o st/pfdxstm.o st/pnpipe.o st/pnpserver.o \ + st/pipbase.o st/pipsvbase.o st/pipstm.o st/pipstmsv.o st/pipmsg.o st/pipmsgsv.o \ + $(EXTRA_OBJS_ST) + +HLEVEL1 = $(INCDIR)/pport.h + +HLEVEL2 = $(HLEVEL1) $(INCDIR)/ptypes.h $(INCDIR)/pasync.h $(INCDIR)/ptime.h + +HLEVEL3 = $(HLEVEL2) $(INCDIR)/pstreams.h + +HLEVEL4 = $(HLEVEL3) $(INCDIR)/pinet.h + +HALL = $(HLEVEL4) + + +all: mtlib shlib stlib ptypes_test ptypesn_test + +mtlib: mt $(LIBNAME) + +shlib: mt $(SOREALNAME) + +stlib: st $(LIBNAME_ST) + + +# +# libptypes +# + +$(LIBNAME): $(LIBOBJS) + $(AR) $@ $(LIBOBJS) + $(RANLIB) $@ + mkdir -p $(LIBDEST) ; cp $@ $(LIBDEST)/ + +$(SOREALNAME): $(LIBOBJS) + $(LIBTOOL) $(LIBOBJS) $(LDLIBS) $(SOINSTOPT) -o $@ + rm -f $(SONAME) ; ln -s $@ $(SONAME) + mkdir -p $(SODEST) ; cp $@ $(SODEST)/ + cd $(SODEST) ; rm -f $(SONAME) ; ln -s $@ $(SONAME) ; $(SOSTRIP) $@ + +$(LIBNAME_ST): $(LIBOBJS_ST) + $(AR) $@ $(LIBOBJS_ST) + $(RANLIB) $@ + mkdir -p $(LIBDEST) ; cp $@ $(LIBDEST)/ + +mt: + if [ ! -d mt ] ; then mkdir mt ; fi + +st: + if [ ! -d st ] ; then mkdir st ; fi + +# +# multithreaded compilation +# + +mt/pversion.o: pversion.cxx $(HLEVEL1) + $(CXX) -c $(CXXOPTS) -o $@ pversion.cxx + +mt/pmem.o: pmem.cxx $(HLEVEL1) + $(CXX) -c $(CXXOPTS) -o $@ pmem.cxx + +mt/pfatal.o: pfatal.cxx $(HLEVEL1) + $(CXX) -c $(CXXOPTS) -o $@ pfatal.cxx + +mt/pstring.o: pstring.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ pstring.cxx + +mt/pcset.o: pcset.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pcset.cxx + +mt/pcsetdbg.o: pcsetdbg.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pcsetdbg.cxx + +mt/pstrmanip.o: pstrmanip.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pstrmanip.cxx + +mt/pstrutils.o: pstrutils.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pstrutils.cxx + +mt/pstrconv.o: pstrconv.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pstrconv.cxx + +mt/pstrtoi.o: pstrtoi.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pstrtoi.cxx + +mt/pstrcase.o: pstrcase.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pstrcase.cxx + +mt/ptime.o: ptime.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ ptime.cxx + +mt/punknown.o: punknown.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ punknown.cxx + +mt/pcomponent.o: pcomponent.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pcomponent.cxx + +mt/pexcept.o: pexcept.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pexcept.cxx + +mt/ppodlist.o: ppodlist.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ ppodlist.cxx + +mt/pobjlist.o: pobjlist.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pobjlist.cxx + +mt/pstrlist.o: pstrlist.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pstrlist.cxx + +mt/ptextmap.o: ptextmap.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ ptextmap.cxx + +mt/patomic.o: patomic.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ patomic.cxx + +mt/pasync.o: pasync.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pasync.cxx + +mt/psemaphore.o: psemaphore.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ psemaphore.cxx + +mt/pthread.o: pthread.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pthread.cxx + +mt/pmsgq.o: pmsgq.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pmsgq.cxx + +mt/ptimedsem.o: ptimedsem.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ ptimedsem.cxx + +mt/prwlock.o: prwlock.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ prwlock.cxx + +mt/ptrigger.o: ptrigger.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ ptrigger.cxx + +mt/pmtxtable.o: pmtxtable.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pmtxtable.cxx + +mt/pvariant.o: pvariant.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS) -o $@ pvariant.cxx + +mt/piobase.o: piobase.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ piobase.cxx + +mt/pinstm.o: pinstm.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ pinstm.cxx + +mt/pinfile.o: pinfile.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ pinfile.cxx + +mt/ppipe.o: ppipe.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ ppipe.cxx + +mt/pintee.o: pintee.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ pintee.cxx + +mt/pinmem.o: pinmem.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ pinmem.cxx + +mt/poutmem.o: poutmem.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ poutmem.cxx + +mt/poutstm.o: poutstm.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ poutstm.cxx + +mt/poutfile.o: poutfile.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ poutfile.cxx + +mt/pinfilter.o: pinfilter.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ pinfilter.cxx + +mt/poutfilter.o: poutfilter.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ poutfilter.cxx + +mt/pmd5.o: pmd5.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ pmd5.cxx + +mt/pputf.o: pputf.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ pputf.cxx + +mt/pstdio.o: pstdio.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ pstdio.cxx + +mt/pfdxstm.o: pfdxstm.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ pfdxstm.cxx + +mt/pnpipe.o: pnpipe.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ pnpipe.cxx + +mt/pnpserver.o: pnpserver.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ pnpserver.cxx + +mt/pipbase.o: pipbase.cxx $(HLEVEL4) + $(CXX) -c $(CXXOPTS) -o $@ pipbase.cxx + +mt/pipsvbase.o: pipsvbase.cxx $(HLEVEL4) + $(CXX) -c $(CXXOPTS) -o $@ pipsvbase.cxx + +mt/pipstm.o: pipstm.cxx $(HLEVEL4) + $(CXX) -c $(CXXOPTS) -o $@ pipstm.cxx + +mt/pipstmsv.o: pipstmsv.cxx $(HLEVEL4) + $(CXX) -c $(CXXOPTS) -o $@ pipstmsv.cxx + +mt/pipmsg.o: pipmsg.cxx $(HLEVEL4) + $(CXX) -c $(CXXOPTS) -o $@ pipmsg.cxx + +mt/pipmsgsv.o: pipmsgsv.cxx $(HLEVEL4) + $(CXX) -c $(CXXOPTS) -o $@ pipmsgsv.cxx + +mt/punit.o: punit.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS) -o $@ punit.cxx + + +# +# single-threaded compilation +# + +st/pversion.o: pversion.cxx $(HLEVEL1) + $(CXX) -c $(CXXOPTS_ST) -o $@ pversion.cxx + +st/pmem.o: pmem.cxx $(HLEVEL1) + $(CXX) -c $(CXXOPTS_ST) -o $@ pmem.cxx + +st/pfatal.o: pfatal.cxx $(HLEVEL1) + $(CXX) -c $(CXXOPTS_ST) -o $@ pfatal.cxx + +st/pstring.o: pstring.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ pstring.cxx + +st/pcset.o: pcset.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ pcset.cxx + +st/pcsetdbg.o: pcsetdbg.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ pcsetdbg.cxx + +st/pstrmanip.o: pstrmanip.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ pstrmanip.cxx + +st/pstrutils.o: pstrutils.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ pstrutils.cxx + +st/pstrconv.o: pstrconv.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ pstrconv.cxx + +st/pstrtoi.o: pstrtoi.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ pstrtoi.cxx + +st/pstrcase.o: pstrcase.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ pstrcase.cxx + +st/ptime.o: ptime.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ ptime.cxx + +st/punknown.o: punknown.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ punknown.cxx + +st/pcomponent.o: pcomponent.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ pcomponent.cxx + +st/pexcept.o: pexcept.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ pexcept.cxx + +st/ppodlist.o: ppodlist.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ ppodlist.cxx + +st/pobjlist.o: pobjlist.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ pobjlist.cxx + +st/pstrlist.o: pstrlist.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ pstrlist.cxx + +st/ptextmap.o: ptextmap.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ ptextmap.cxx + +st/patomic.o: patomic.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ patomic.cxx + +st/pvariant.o: pvariant.cxx $(HLEVEL2) + $(CXX) -c $(CXXOPTS_ST) -o $@ pvariant.cxx + +st/piobase.o: piobase.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ piobase.cxx + +st/pinstm.o: pinstm.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ pinstm.cxx + +st/pinfile.o: pinfile.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ pinfile.cxx + +st/ppipe.o: ppipe.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ ppipe.cxx + +st/pintee.o: pintee.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ pintee.cxx + +st/pinmem.o: pinmem.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ pinmem.cxx + +st/poutmem.o: poutmem.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ poutmem.cxx + +st/poutstm.o: poutstm.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ poutstm.cxx + +st/poutfile.o: poutfile.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ poutfile.cxx + +st/pinfilter.o: pinfilter.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ pinfilter.cxx + +st/poutfilter.o: poutfilter.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ poutfilter.cxx + +st/pmd5.o: pmd5.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ pmd5.cxx + +st/pputf.o: pputf.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ pputf.cxx + +st/pstdio.o: pstdio.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ pstdio.cxx + +st/pfdxstm.o: pfdxstm.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ pfdxstm.cxx + +st/pnpipe.o: pnpipe.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ pnpipe.cxx + +st/pnpserver.o: pnpserver.cxx $(HLEVEL3) + $(CXX) -c $(CXXOPTS_ST) -o $@ pnpserver.cxx + +st/pipbase.o: pipbase.cxx $(HLEVEL4) + $(CXX) -c $(CXXOPTS_ST) -o $@ pipbase.cxx + +st/pipsvbase.o: pipsvbase.cxx $(HLEVEL4) + $(CXX) -c $(CXXOPTS_ST) -o $@ pipsvbase.cxx + +st/pipstm.o: pipstm.cxx $(HLEVEL4) + $(CXX) -c $(CXXOPTS_ST) -o $@ pipstm.cxx + +st/pipstmsv.o: pipstmsv.cxx $(HLEVEL4) + $(CXX) -c $(CXXOPTS_ST) -o $@ pipstmsv.cxx + +st/pipmsg.o: pipmsg.cxx $(HLEVEL4) + $(CXX) -c $(CXXOPTS_ST) -o $@ pipmsg.cxx + +st/pipmsgsv.o: pipmsgsv.cxx $(HLEVEL4) + $(CXX) -c $(CXXOPTS_ST) -o $@ pipmsgsv.cxx + + + +# +# libptypes test program +# + +mt/ptypes_test.o: ptypes_test.cxx $(HALL) + $(CXX) -c $(CXXOPTS) -o $@ ptypes_test.cxx + +ptypes_test: mt/ptypes_test.o $(LIBNAME) + $(CXX) $(CXXOPTS) mt/ptypes_test.o -L./ libptypes.a $(LDLIBS) -o $@ + +st/ptypes_test.o: ptypes_test.cxx $(HALL) + $(CXX) -c $(CXXOPTS_ST) -o $@ ptypes_test.cxx + +ptypesn_test: st/ptypes_test.o $(LIBNAME) + $(CXX) $(CXXOPTS_ST) st/ptypes_test.o -L./ libptypesn.a $(LDLIBS_ST) -o $@ + + +# +# clean +# + +clean: clean-src + rm -f $(LIBDEST)/$(LIBNAME) $(LIBDEST)/$(LIBNAME_ST) + rm -f $(SODEST)/$(SONAME) $(SODEST)/$(SOREALNAME) + +clean-src: + rm -rf mt st + rm -f $(LIBNAME) $(LIBNAME_ST) $(SONAME) $(SOREALNAME) + rm -f core *.core core.* + rm -f ptypes_test ptypesn_test ptypes_test.exe ptypesn_test.exe + rm -f stmtest.txt + +# +# install +# + +install: $(LIBNAME) $(SOREALNAME) ${LIBNAME_ST} + @echo ; echo "##### Installing header files in ${PREFIX}/include/ptypes" + mkdir -p ${PREFIX}/include/ptypes + install -m 444 ${INCDIR}/*.h ${PREFIX}/include/ptypes + @echo ; echo "##### Installing libraries (libptypes*) in ${PREFIX}/lib" + mkdir -p ${PREFIX}/lib + install -m 444 $(LIBDEST)/$(LIBNAME) $(LIBDEST)/$(LIBNAME_ST) ${PREFIX}/lib + install -m 444 $(SODEST)/$(SOREALNAME) ${PREFIX}/lib + cd ${PREFIX}/lib ; rm -f ${SONAME} ; ln -s ${SOREALNAME} ${SONAME} + @echo ; echo "##### Installing documentation in ${PREFIX}/share/doc/ptypes/doc" + mkdir -p ${PREFIX}/share/doc/ptypes/doc + cd .. ; install -m 444 LICENSE index.html ${PREFIX}/share/doc/ptypes + cd ../doc ; tar cf - * | tar xf - -C ${PREFIX}/share/doc/ptypes/doc + +uninstall: + rm -rf ${PREFIX}/include/ptypes + cd ${PREFIX}/lib ; rm -f $(LIBNAME) $(LIBNAME_ST) $(SONAME) $(SOREALNAME) + rm -rf ${PREFIX}/share/doc/ptypes diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pasync.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pasync.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,61 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +# include +# include +# ifdef __sun__ +# include +# endif +#endif + +#include "pasync.h" + + +PTYPES_BEGIN + + +void ptdecl psleep(uint milliseconds) +{ +#if defined(WIN32) + Sleep(milliseconds); +#elif defined(__sun__) + poll(0, 0, milliseconds); +#else + usleep(milliseconds * 1000); +#endif +} + + +pthread_id_t ptdecl pthrself() +{ +#ifdef WIN32 + return (int)GetCurrentThreadId(); +#else + return pthread_self(); +#endif +} + + +bool ptdecl pthrequal(pthread_id_t id) +{ +#ifdef WIN32 + return GetCurrentThreadId() == (uint)id; +#else + return pthread_equal(pthread_self(), id); +#endif +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/patomic.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/patomic.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,354 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#endif + +#include "ptypes.h" +#include "pasync.h" // for pmemlock* + + +PTYPES_BEGIN + + +#ifdef PTYPES_ST +// single-threaded version + + +int __PFASTCALL pexchange(int* target, int value) +{ + int r = *target; + *target = value; + return r; +} + + +void* __PFASTCALL pexchange(void** target, void* value) +{ + void* r = *target; + *target = value; + return r; +} + + +int __PFASTCALL pincrement(int* target) +{ + return ++(*target); +} + + +int __PFASTCALL pdecrement(int* target) +{ + return --(*target); +} + + +#else +// multi-threaded version + +#if defined(__GNUC__) && (defined(__i386__) || defined(__I386__)) +# define GCC_i386 +#elif defined(__GNUC__) && defined(__ppc__) +# define GCC_PPC +#elif defined(_MSC_VER) && defined(_M_IX86) +# define MSC_i386 +#elif defined(__BORLANDC__) && defined(_M_IX86) +# define BCC_i386 +#elif defined(__GNUC__) && defined(__sparc__) && !defined(__arch64__) +# define GCC_sparc +#endif + + +#if defined(MSC_i386) || defined(BCC_i386) + +// +// atomic operations for Microsoft C or Borland C on Windows +// + +#if defined(_MSC_VER) +# pragma warning (disable: 4035) +#elif defined(__BORLANDC__) +# pragma warn -rvl +#endif + + +// !!! NOTE +// the following functions implement atomic exchange/inc/dec on +// windows. they are dangerous in that they rely on the calling +// conventions of MSVC and BCC. the first one passes the first +// two arguments in ECX and EDX, and the second one - in EAX and +// EDX. + +int __PFASTCALL pincrement(int*) +{ + __asm + { +#ifdef BCC_i386 + mov ecx,eax +#endif + mov eax,1; + lock xadd [ecx],eax; + inc eax + } +} + + +int __PFASTCALL pdecrement(int*) +{ + __asm + { +#ifdef BCC_i386 + mov ecx,eax +#endif + mov eax,-1; + lock xadd [ecx],eax; + dec eax + } +} + + +int __PFASTCALL pexchange(int*, int) +{ + __asm + { +#ifdef BCC_i386 + xchg eax,edx; + lock xchg eax,[edx]; +#else + mov eax,edx; + lock xchg eax,[ecx]; +#endif + } +} + + +void* __PFASTCALL pexchange(void**, void*) +{ + __asm + { +#ifdef BCC_i386 + xchg eax,edx; + lock xchg eax,[edx]; +#else + mov eax,edx; + lock xchg eax,[ecx]; +#endif + } +} + + +#elif defined(GCC_i386) + +// +// GNU C compiler on any i386 platform (actually 486+ for xadd) +// + +int pexchange(int* target, int value) +{ + __asm__ __volatile ("lock ; xchgl (%1),%0" : "+r" (value) : "r" (target)); + return value; +} + + +void* pexchange(void** target, void* value) +{ + __asm__ __volatile ("lock ; xchgl (%1),%0" : "+r" (value) : "r" (target)); + return value; +} + + +int pincrement(int* target) +{ + int temp = 1; + __asm__ __volatile ("lock ; xaddl %0,(%1)" : "+r" (temp) : "r" (target)); + return temp + 1; +} + + +int pdecrement(int* target) +{ + int temp = -1; + __asm__ __volatile ("lock ; xaddl %0,(%1)" : "+r" (temp) : "r" (target)); + return temp - 1; +} + + +#elif defined(GCC_PPC) + +// +// GNU C compiler on any PPC platform +// + +int pexchange(int* target, int value) +{ + int temp; + __asm__ __volatile ( +"1: lwarx %0,0,%1\n\ + stwcx. %2,0,%1\n\ + bne- 1b\n\ + isync" + : "=&r" (temp) + : "r" (target), "r" (value) + : "cc", "memory" + ); + return temp; +} + + +void* pexchange(void** target, void* value) +{ + void* temp; + __asm__ __volatile ( +"1: lwarx %0,0,%1\n\ + stwcx. %2,0,%1\n\ + bne- 1b\n\ + isync" + : "=&r" (temp) + : "r" (target), "r" (value) + : "cc", "memory" + ); + return temp; +} + + +int pincrement(int* target) +{ + int temp; + __asm__ __volatile ( +"1: lwarx %0,0,%1\n\ + addic %0,%0,1\n\ + stwcx. %0,0,%1\n\ + bne- 1b\n\ + isync" + : "=&r" (temp) + : "r" (target) + : "cc", "memory" + ); + return temp; +} + + +int pdecrement(int* target) +{ + int temp; + __asm__ __volatile ( +"1: lwarx %0,0,%1\n\ + addic %0,%0,-1\n\ + stwcx. %0,0,%1\n\ + bne- 1b\n\ + isync" + : "=&r" (temp) + : "r" (target) + : "cc", "memory" + ); + return temp; +} + + +#elif defined GCC_sparc + +// +// GNU C compiler on SPARC in 32-bit mode (pointers are 32-bit) +// + +// assembly routines defined in patomic.sparc.s +// we currently don't use CAS in the library, but let it be there +extern "C" { + int __patomic_add(volatile int* __mem, int __val); + int __patomic_swap(volatile int* __mem, int __val); + int __patomic_cas(volatile int* __mem, int __expected, int __newval); +} + +#define __patomic_swap_p(mem,val) \ + (void*)(__patomic_swap((int*)(mem), (int)(val))) + + +int pexchange(int* target, int value) +{ + return __patomic_swap(target, value); +} + + +void* pexchange(void** target, void* value) +{ + return __patomic_swap_p(target, value); +} + + +int pincrement(int* target) +{ + return __patomic_add(target, 1); +} + + +int pdecrement(int* target) +{ + return __patomic_add(target, -1); +} + + + + +#else + +// +// other platforms: mutex locking +// + +int pexchange(int* target, int value) +{ + pmemlock* m = pgetmemlock(target); + pmementer(m); + int r = *target; + *target = value; + pmemleave(m); + return r; +} + + +void* pexchange(void** target, void* value) +{ + pmemlock* m = pgetmemlock(target); + pmementer(m); + void* r = *target; + *target = value; + pmemleave(m); + return r; +} + + +int pincrement(int* target) +{ + pmemlock* m = pgetmemlock(target); + pmementer(m); + int r = ++(*target); + pmemleave(m); + return r; +} + + +int pdecrement(int* target) +{ + pmemlock* m = pgetmemlock(target); + pmementer(m); + int r = --(*target); + pmemleave(m); + return r; +} + +#endif + + +#endif + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/patomic.sparc.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/patomic.sparc.s Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,42 @@ + + .section ".text" + .align 4 + .global __patomic_add + .type __patomic_add, #function +__patomic_add: + ld [%o0], %o2 +1: + add %o2, %o1, %o3 + cas [%o0], %o2, %o3 + cmp %o2, %o3 + bne,a,pn %icc, 1b + mov %o3, %o2 + retl + add %o2, %o1, %o0 ! return new value + .size __patomic_add, .-__patomic_add + + .section ".text" + .align 4 + .global __patomic_swap + .type __patomic_swap, #function +__patomic_swap: + ld [%o0], %o2 +1: + mov %o1, %o3 + cas [%o0], %o2, %o3 + cmp %o2, %o3 + bne,a,pn %icc, 1b + mov %o3, %o2 + retl + mov %o3, %o0 + .size __patomic_swap, .-__patomic_swap + + .section ".text" + .align 4 + .global __patomic_cas + .type __patomic_cas, #function +__patomic_cas: + cas [%o0], %o1, %o2 + retl + mov %o2, %o0 + .size __patomic_cas, .-__patomic_cas diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pcomponent.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pcomponent.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,102 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "ptypes.h" + + +PTYPES_BEGIN + + +component::component() + : unknown(), refcount(0), freelist(nil), typeinfo(nil) {} + + +component::~component() +{ + if (freelist != nil) + { + for (int i = 0; i < freelist->get_count(); i++) + (*freelist)[i]->freenotify(this); + delete freelist; + freelist = nil; + } +} + + +void component::freenotify(component*) +{ +} + + +void component::addnotification(component* obj) +{ + if (freelist == nil) + freelist = new tobjlist(false); + freelist->add(obj); +} + + +void component::delnotification(component* obj) +{ + int i = -1; + if (freelist != nil) + { + i = freelist->indexof(obj); + if (i >= 0) { + freelist->del(i); + if (freelist->get_count() == 0) + { + delete freelist; + freelist = nil; + } + } + } + if (i == -1) + fatal(CRIT_FIRST + 1, "delnotification() failed: no such object"); +} + + +int component::classid() +{ + return CLASS_UNDEFINED; +} + + +component* ptdecl addref(component* c) +{ + if (c != nil) +#ifdef PTYPES_ST + c->refcount++; +#else + pincrement(&c->refcount); +#endif + return c; +} + + +bool ptdecl release(component* c) +{ + if (c != nil) + { +#ifdef PTYPES_ST + if (--c->refcount == 0) +#else + if (pdecrement(&c->refcount) == 0) +#endif + delete c; + else + return false; + } + return true; +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pcset.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pcset.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,139 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "ptypes.h" + + +PTYPES_BEGIN + + +typedef int* pint; + + +static uchar lbitmask[8] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80}; +static uchar rbitmask[8] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; + + +void cset::include(char min, char max) +{ + if (uchar(min) > uchar(max)) + return; + int lidx = uchar(min) / 8; + int ridx = uchar(max) / 8; + uchar lbits = lbitmask[uchar(min) % 8]; + uchar rbits = rbitmask[uchar(max) % 8]; + + if (lidx == ridx) + { + data[lidx] |= lbits & rbits; + } + else + { + data[lidx] |= lbits; + for (int i = lidx + 1; i < ridx; i++) + data[i] = -1; + data[ridx] |= rbits; + } + +} + + +char hex4(char c) +{ + if (c >= 'a') + return uchar(c - 'a' + 10); + else if (c >= 'A') + return uchar(c - 'A' + 10); + else + return char(c - '0'); +} + + +static uchar parsechar(const char*& p) +{ + uchar ret = *p; + if (ret == _csetesc) { + p++; + ret = *p; + if ((ret >= '0' && ret <= '9') || (ret >= 'a' && ret <= 'f') || (ret >= 'A' && ret <= 'F')) { + ret = hex4(ret); + p++; + if (*p != 0) + ret = uchar((ret << 4) | hex4(*p)); + } + } + return ret; +} + + +void cset::assign(const char* p) +{ + if (*p == '*' && *(p + 1) == 0) + fill(); + else + { + clear(); + for (; *p != 0; p++) { + uchar left = parsechar(p); + if (*(p + 1) == '-') { + p += 2; + uchar right = parsechar(p); + include(left, right); + } + else + include(left); + } + } +} + + +void cset::unite(const cset& s) +{ + for(int i = 0; i < _csetwords; i++) + *(pint(data) + i) |= *(pint(s.data) + i); +} + + +void cset::subtract(const cset& s) +{ + for(int i = 0; i < _csetwords; i++) + *(pint(data) + i) &= ~(*(pint(s.data) + i)); +} + + +void cset::intersect(const cset& s) +{ + for(int i = 0; i < _csetwords; i++) + *(pint(data) + i) &= *(pint(s.data) + i); +} + + +void cset::invert() +{ + for(int i = 0; i < _csetwords; i++) + *(pint(data) + i) = ~(*(pint(data) + i)); +} + + +bool cset::le(const cset& s) const +{ + for (int i = 0; i < _csetwords; i++) + { + int w1 = *(pint(data) + i); + int w2 = *(pint(s.data) + i); + if ((w2 | w1) != w2) + return false; + } + return true; +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pcsetdbg.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pcsetdbg.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,78 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "ptypes.h" + + +PTYPES_BEGIN + + +static char hexchar(uchar c) +{ + if (c < 10) + return char(c + '0'); + else + return char(c - 10 + 'a'); +} + + +inline bool isprintable(uchar c) +{ + return ((c >= ' ') && (c < 127)); +} + + +static string showmember(uchar c) +{ + if ((c == '-') || (c == '~')) + return string('~') + string(c); + else if (isprintable(c)) + return c; + else + { + string ret = "~ "; + ret[1] = hexchar(uchar(c >> 4)); + ret[2] = hexchar(uchar(c & 0x0f)); + return ret; + } +} + + +string ptdecl asstring(const cset& s) +{ + string ret; + int l = -1, r = -1; + for(int i = 0; i <= _csetbits; i++) + { + if (i < _csetbits && uchar(i) & s) + { + if (l == -1) + l = i; + else + r = i; + } + else if (l != -1) + { + concat(ret, showmember(uchar(l))); + if (r != -1) { + if (r > l + 1) + concat(ret, '-'); + concat(ret, showmember(uchar(r))); + } + l = -1; + r = -1; + } + } + return ret; +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pexcept.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pexcept.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,35 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "ptypes.h" + + +PTYPES_BEGIN + + +exception::exception(const char* imsg) + : message(imsg) +{ +} + + +exception::exception(const string& imsg) + : message(imsg) +{ +} + + +exception::~exception() +{ +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pfatal.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pfatal.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,63 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include +#include +#include + +#include "pport.h" + +#if defined(WIN32) && !defined(NO_CRIT_MSGBOX) +# include +# define CRIT_MSGBOX +#endif + + +PTYPES_BEGIN + + +static void ptdecl defhandler(int code, const char* msg) +{ +#ifdef CRIT_MSGBOX + char buf[2048]; + _snprintf(buf, sizeof(buf) - 1, "Fatal [%05x]: %s", code, msg); + MessageBox(0, buf, "Internal error", MB_OK | MB_ICONSTOP); +#else + fprintf(stderr, "\nInternal [%04x]: %s\n", code, msg); +#endif +} + +static _pcrithandler crith = defhandler; + + +_pcrithandler ptdecl getcrithandler() +{ + return crith; +} + + +_pcrithandler ptdecl setcrithandler(_pcrithandler newh) +{ + _pcrithandler ret = crith; + crith = newh; + return ret; +} + + +void ptdecl fatal(int code, const char* msg) +{ + if (crith != nil) + (*crith)(code, msg); + exit(code); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pfdxstm.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pfdxstm.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,162 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +#endif + +#include "pstreams.h" + + +PTYPES_BEGIN + + +#ifdef _MSC_VER +// disable "'this' : used in base member initializer list" warning +# pragma warning (disable: 4355) +#endif + + +fdxoutstm::fdxoutstm(int ibufsize, fdxstm* iin) + : outstm(false, ibufsize), in(iin) {} + + +fdxoutstm::~fdxoutstm() {} + + +void fdxoutstm::chstat(int newstat) +{ + outstm::chstat(newstat); + if (newstat == IO_WRITING) + in->chstat(newstat); +} + + +int fdxoutstm::uerrno() +{ + return in->uerrno(); +} + + +const char* fdxoutstm::uerrmsg(int code) +{ + return in->uerrmsg(code); +} + + +string fdxoutstm::get_streamname() +{ + return in->get_streamname(); +} + + +void fdxoutstm::doopen() +{ +} + + +void fdxoutstm::doclose() +{ + if (in->active) + in->close(); +} + + +int fdxoutstm::dorawwrite(const char* buf, int count) +{ + return in->dorawwrite(buf, count); +} + + +fdxstm::fdxstm(int ibufsize) + : instm(ibufsize), out(ibufsize, this) +{ + out.in = this; + addref(&out); +} + + +fdxstm::~fdxstm() {} + + +int fdxstm::classid() +{ + return CLASS2_FDX; +} + + +void fdxstm::flush() +{ + if (out.active) + out.flush(); +} + + +int fdxstm::dorawwrite(const char* buf, int count) +{ + if (handle == invhandle) + return -1; +#ifdef WIN32 + unsigned long ret; + if (!WriteFile(HANDLE(handle), buf, count, &ret, nil)) + { + error(uerrno(), "Couldn't write"); + ret = uint(-1); + } +#else + int ret; + if ((ret = ::write(handle, buf, count)) < 0) + error(uerrno(), "Couldn't write"); +#endif + return ret; +} + + +void fdxstm::set_bufsize(int newval) +{ + instm::set_bufsize(newval); + out.set_bufsize(newval); +} + + +void fdxstm::open() +{ + instm::open(); + out.open(); +} + + +void fdxstm::close() +{ + instm::close(); + out.close(); +} + + +void fdxstm::cancel() +{ + instm::cancel(); + out.cancel(); +} + + +large fdxstm::tellx(bool forin) +{ + if (forin) + return instm::tellx(); + else + return out.tellx(); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pinfile.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pinfile.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,93 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +# include +#endif + +#include "pstreams.h" + + +PTYPES_BEGIN + + +// *BSD hack +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif + + +infile::infile() + : instm(), filename(), syshandle(invhandle), peerhandle(invhandle) {} + + +infile::infile(const char* ifn) + : instm(), filename(ifn), syshandle(invhandle), peerhandle(invhandle) {} + + +infile::infile(const string& ifn) + : instm(), filename(ifn), syshandle(invhandle), peerhandle(invhandle) {} + + +infile::~infile() +{ + close(); +} + + +int infile::classid() +{ + return CLASS2_INFILE; +} + + +string infile::get_streamname() +{ + return filename; +} + + +void infile::doopen() +{ + if (syshandle != invhandle) + handle = syshandle; + else + { +#ifdef WIN32 + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + handle = int(CreateFile(filename, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, 0)); +#else + handle = ::open(filename, O_RDONLY | O_LARGEFILE); +#endif + if (handle == invhandle) + error(uerrno(), "Couldn't open"); + } +} + + +void infile::doclose() +{ + instm::doclose(); + syshandle = invhandle; + peerhandle = invhandle; +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pinfilter.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pinfilter.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,170 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include + +#include "pstreams.h" + + +PTYPES_BEGIN + + +string infilter::get_errstmname() +{ + if (stm == nil) + return get_streamname(); + else + return get_streamname() + ": " + stm->get_errstmname(); +} + + +void infilter::copytobuf(string& s) +{ + int n = imin(savecount, length(s)); + if (n > 0) + { + memcpy(savebuf, pconst(s), n); + savebuf += n; + savecount -= n; + if (n == savecount) + clear(s); + else + del(s, 0, n); + } +} + + +void infilter::copytobuf(pconst& buf, int& count) +{ + int n = imin(savecount, count); + if (n > 0) + { + memcpy(savebuf, buf, n); + savebuf += n; + savecount -= n; + buf += n; + count -= n; + } +} + + +bool infilter::copytobuf(char c) +{ + if (savecount > 0) { + *savebuf = c; + savebuf++; + savecount--; + return true; + } + else + return false; +} + + +infilter::infilter(instm* istm, int ibufsize) + : instm(ibufsize), stm(istm), savebuf(nil), savecount(0) +{ + if (stm != nil) + stm->addnotification(this); +} + + +infilter::~infilter() +{ + if (stm != nil) + stm->delnotification(this); +} + + +void infilter::freenotify(component* sender) +{ + if (sender == stm) + { + stm = nil; + close(); + } +} + + +void infilter::doopen() +{ + if (stm != nil && !stm->get_active()) + stm->open(); +} + + +void infilter::doclose() +{ + savebuf = nil; + savecount = 0; + clear(postponed); +} + + +void infilter::set_stm(instm* istm) +{ + close(); + if (stm != nil) + stm->delnotification(this); + stm = istm; + if (stm != nil) + stm->addnotification(this); +} + + +int infilter::dorawread(char* buf, int count) +{ + savebuf = buf; + savecount = count; + if (!isempty(postponed)) + copytobuf(postponed); + if (savecount > 0 && stm != nil) + dofilter(); + return count - savecount; +} + + +void infilter::post(const char* buf, int count) +{ + if (count > 0) + { + copytobuf(buf, count); + if (count > 0) + concat(postponed, buf, count); + } +} + + +void infilter::post(string s) +{ + if (!isempty(s)) + { + copytobuf(s); + if (!isempty(s)) + concat(postponed, s); + } +} + + +void infilter::post(const char* s) +{ + post(s, strlen(s)); +} + + +void infilter::post(char c) +{ + if (!copytobuf(c)) + concat(postponed, c); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pinmem.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pinmem.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,104 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "pstreams.h" + + +PTYPES_BEGIN + + +inmemory::inmemory(const string& imem) + : instm(length(imem)), mem(imem) +{ +} + + +inmemory::~inmemory() +{ + close(); +} + + +int inmemory::classid() +{ + return CLASS2_INMEMORY; +} + + +void inmemory::bufalloc() +{ + bufdata = pchar(pconst(mem)); + abspos = bufsize = bufend = length(mem); +} + + +void inmemory::buffree() +{ + bufclear(); + bufdata = nil; +} + + +void inmemory::bufvalidate() +{ + eof = bufpos >= bufend; +} + + +void inmemory::doopen() +{ +} + + +void inmemory::doclose() +{ +} + + +large inmemory::doseek(large, ioseekmode) +{ + // normally shouldn't reach this point, because seek is + // supposed to happen within the I/O buffer + return -1; +} + + +int inmemory::dorawread(char*, int) +{ + return 0; +} + + +string inmemory::get_streamname() +{ + return "mem"; +} + + +large inmemory::seekx(large newpos, ioseekmode mode) +{ + if (mode == IO_END) + { + newpos += bufsize; + mode = IO_BEGIN; + } + return instm::seekx(newpos, mode); +} + + +void inmemory::set_strdata(const string& data) +{ + close(); + mem = data; +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pinstm.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pinstm.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,350 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include +#include +#include + +#ifdef WIN32 +# include +#else +# include +#endif + +#include "pstreams.h" + + +PTYPES_BEGIN + + +instm::instm(int ibufsize): iobase(ibufsize) +{ +} + + +instm::~instm() +{ +} + + +int instm::classid() +{ + return CLASS_INSTM; +} + + +int instm::dorawread(char* buf, int count) +{ + if (handle == invhandle) + return -1; +#ifdef WIN32 + unsigned long ret; + if (!ReadFile(HANDLE(handle), buf, count, &ret, nil)) +#else + int ret; + if ((ret = ::read(handle, buf, count)) < 0) +#endif + { + int e = uerrno(); + if (e == EPIPE) + ret = 0; + else + error(e, "Couldn't read"); + } + return ret; +} + + +int instm::rawread(char* buf, int count) +{ + requireactive(); + try + { + int ret = dorawread(buf, count); + if (ret <= 0) { + ret = 0; + eof = true; + chstat(IO_EOF); + } + else + { + abspos += ret; + chstat(IO_READING); + } + return ret; + } + catch (estream*) + { + eof = true; + chstat(IO_EOF); + throw; + } +} + + +large instm::tellx() +{ + return abspos - bufend + bufpos; +} + + +void instm::bufvalidate() +{ + requirebuf(); + bufclear(); + bufend = rawread(bufdata, bufsize); +} + + +large instm::seekx(large newpos, ioseekmode mode) +{ + if (bufdata != 0 && mode != IO_END) + { + if (mode == IO_CURRENT) + { + newpos += tellx(); + mode = IO_BEGIN; + } + + // see if it is possible to seek within the buffer + large newbufpos = newpos - (abspos - bufend); + if (newbufpos >= 0 && newbufpos <= bufend) + { + bufpos = (int)newbufpos; + eof = false; + return tellx(); + } + } + + // if IO_END or if not possible to seek within the buffer + return iobase::seekx(newpos, mode); +} + + +bool instm::get_eof() +{ + if (!eof && bufdata != 0 && bufpos >= bufend) + bufvalidate(); + return eof; +} + + +int instm::get_dataavail() +{ + get_eof(); + return bufend - bufpos; +} + + +char instm::preview() +{ + if (!eof && bufpos >= bufend) + bufvalidate(); + if (eof) + return eofchar; + return bufdata[bufpos]; +} + + +void instm::putback() +{ + requireactive(); + if (bufpos == 0) + fatal(CRIT_FIRST + 14, "putback() failed"); + bufpos--; + eof = false; +} + + +bool instm::get_eol() +{ + char c = preview(); + return (eof || c == 10 || c == 13); +} + + +void instm::skipeol() +{ + switch (preview()) + { + case 10: + get(); + break; + case 13: + get(); + if (preview() == 10) + get(); + break; + } +} + + +char instm::get() +{ + char ret = preview(); + if (!eof) + bufpos++; + return ret; +} + + +string instm::token(const cset& chars, int limit) +{ + requirebuf(); + string ret; + while (!get_eof()) + { + char* b = bufdata + bufpos; + char* e = bufdata + bufend; + char* p = b; + while (p < e && (*p & chars)) + p++; + int n = p - b; + limit -= n; + if (limit < 0) + { + bufpos += n + limit; + error(ERANGE, "Token too long"); + } + concat(ret, b, n); + bufpos += n; + if (p < e) + break; + } + return ret; +} + + +string instm::token(const cset& chars) +{ + return token(chars, INT_MAX); +} + + +static cset linechars = cset("*") - cset("~0a~0d"); + + +string instm::line(int limit) +{ + string ret = token(linechars, limit); + skipeol(); + return ret; +} + + +string instm::line() +{ + string ret = token(linechars, INT_MAX); + skipeol(); + return ret; +} + + +int instm::token(const cset& chars, char* buf, int count) +{ + requirebuf(); + int ret = 0; + while (count > 0 && !get_eof()) + { + char* b = bufdata + bufpos; + char* e = b + imin(count, bufend - bufpos); + char* p = b; + while (p < e && (*p & chars)) + p++; + int n = p - b; + memcpy(buf, b, n); + buf += n; + ret += n; + count -= n; + bufpos += n; + if (p < e) + break; + } + return ret; +} + + +int instm::line(char* buf, int size, bool eateol) +{ + int ret = token(linechars, buf, size); + if (eateol) + skipeol(); + return ret; +} + + +int instm::read(void* buf, int count) +{ + int ret = 0; + if (bufdata == 0) + ret = rawread(pchar(buf), count); + else + { + while (count > 0 && !get_eof()) + { + int n = imin(count, bufend - bufpos); + memcpy(buf, bufdata + bufpos, n); + buf = pchar(buf) + n; + ret += n; + count -= n; + bufpos += n; + } + } + return ret; +} + + +int instm::skip(int count) +{ + int ret = 0; + requirebuf(); + while (count > 0 && !get_eof()) + { + int n = imin(count, bufend - bufpos); + ret += n; + count -= n; + bufpos += n; + } + return ret; +} + + +int instm::skiptoken(const cset& chars) +{ + int ret = 0; + requirebuf(); + while (!get_eof()) + { + char* b = bufdata + bufpos; + char* e = bufdata + bufend; + char* p = b; + while (p < e && (*p & chars)) + p++; + int n = p - b; + bufpos += n; + ret += n; + if (p < e) + break; + } + return ret; +} + + +void instm::skipline(bool eateol) +{ + if (!get_eol()) + skiptoken(linechars); + if (eateol) + skipeol(); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pintee.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pintee.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,68 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "pstreams.h" + + +PTYPES_BEGIN + + +intee::intee(instm* istm, const char* ifn, bool iappend) + : infilter(istm, -1), file(ifn, iappend) +{ +} + + +intee::intee(instm* istm, const string& ifn, bool iappend) + : infilter(istm, -1), file(ifn, iappend) +{ +} + + +intee::~intee() +{ + close(); +} + + +void intee::doopen() +{ + infilter::doopen(); + file.open(); +} + + +void intee::doclose() +{ + file.close(); + infilter::doclose(); +} + + +void intee::dofilter() +{ + int count = stm->read(savebuf, savecount); + if (count > 0) + { + file.write(savebuf, count); + savebuf += count; + savecount -= count; + } +} + + +string intee::get_streamname() +{ + return "tee: " + file.get_filename(); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/piobase.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/piobase.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,386 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include +#include + +#ifdef WIN32 +# include +#else +# include +# include +#endif + +#include "pstreams.h" + + +PTYPES_BEGIN + + +/* + +Known UNIX error codes: + +EPERM 1 Not owner +ENOENT 2 No such file or directory +ESRCH 3 No such process +EINTR 4 Interrupted system call +EIO 5 I/O error +ENXIO 6 No such device or address +E2BIG 7 Argument list too long +ENOEXEC 8 Exec format error +EBADF 9 Bad file number +ECHILD 10 No spawned processes +EAGAIN 11 No more processes; not enough memory; maximum nesting level reached +ENOMEM 12 Not enough memory +EACCES 13 Permission denied +EFAULT 14 Bad address +ENOTBLK 15 Block device required +EBUSY 16 Mount device busy +EEXIST 17 File exists +EXDEV 18 Cross-device link +ENODEV 19 No such device +ENOTDIR 20 Not a directory +EISDIR 21 Is a directory +EINVAL 22 Invalid argument +ENFILE 23 File table overflow +EMFILE 24 Too many open files +ENOTTY 25 Not a teletype +ETXTBSY 26 Text file busy +EFBIG 27 File too large +ENOSPC 28 No space left on device +ESPIPE 29 Illegal seek +EROFS 30 Read-only file system +EMLINK 31 Too many links +EPIPE 32 Broken pipe +EDOM 33 Math argument +ERANGE 34 Result too large +EUCLEAN 35 File system needs cleaning +EDEADLK 36 Resource deadlock would occur +EDEADLOCK 36 Resource deadlock would occur + +*/ + + +#ifndef WIN32 + +static class _io_init +{ +public: + _io_init(); +} _io_init_inst; + + +_io_init::_io_init() +{ + // We don't like broken pipes. PTypes will throw an exception instead. + signal(SIGPIPE, SIG_IGN); +} + +#endif + + + +int ptdecl unixerrno() +{ +#ifdef WIN32 + switch(GetLastError()) + { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: return ENOENT; + case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: return EACCES; + case ERROR_INVALID_HANDLE: return EBADF; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_OUTOFMEMORY: return ENOMEM; + case ERROR_INVALID_DRIVE: return ENODEV; + case ERROR_WRITE_PROTECT: return EROFS; + case ERROR_FILE_EXISTS: return EEXIST; + case ERROR_BROKEN_PIPE: return EPIPE; + case ERROR_DISK_FULL: return ENOSPC; + case ERROR_SEEK_ON_DEVICE: return ESPIPE; + default: return EIO; + } +#else + return errno; +#endif +} + + +// +// This function gives error messages for most frequently occurring +// IO errors. If the function returns NULL a generic message +// can be given, e.g. "I/O error". See also iobase::get_errormsg() +// + +const char* ptdecl unixerrmsg(int code) +{ + switch(code) + { + case EBADF: return "Invalid file descriptor"; + case ESPIPE: return "Can not seek on this device"; + case ENOENT: return "No such file or directory"; + case EMFILE: return "Too many open files"; + case EACCES: return "Access denied"; + case ENOMEM: return "Not enough memory"; + case ENODEV: return "No such device"; + case EROFS: return "Read-only file system"; + case EEXIST: return "File already exists"; + case ENOSPC: return "Disk full"; + case EPIPE: return "Broken pipe"; + case EFBIG: return "File too large"; + default: return nil; + } +} + + +estream::estream(iobase* ierrstm, int icode, const char* imsg) + : exception(imsg), code(icode), errstm(ierrstm) {} + + +estream::estream(iobase* ierrstm, int icode, const string& imsg) + : exception(imsg), code(icode), errstm(ierrstm) {} + + +estream::~estream() {} + + +int defbufsize = 8192; +int stmbalance = 0; + +iobase::iobase(int ibufsize) + : component(), active(false), cancelled(false), eof(true), + handle(invhandle), abspos(0), bufsize(0), bufdata(nil), bufpos(0), bufend(0), + stmerrno(0), deferrormsg(), status(IO_CREATED), onstatus(nil) +{ + if (ibufsize < 0) + bufsize = defbufsize; + else + bufsize = ibufsize; +} + + +iobase::~iobase() +{ +} + + +void iobase::bufalloc() +{ + if (bufdata != nil) + fatal(CRIT_FIRST + 13, "(ptypes internal) invalid buffer allocation"); + bufdata = (char*)memalloc(bufsize); +} + + +void iobase::buffree() +{ + bufclear(); + memfree(bufdata); + bufdata = 0; +} + + +void iobase::chstat(int newstat) +{ + status = newstat; + if (onstatus != nil) + (*onstatus)(this, newstat); +} + + +void iobase::errstminactive() +{ + error(EIO, "Stream inactive"); +} + + +void iobase::errbufrequired() +{ + fatal(CRIT_FIRST + 11, "Internal: buffer required"); +} + + +int iobase::convertoffset(large offs) +{ + if (offs < 0 || offs > INT_MAX) + error(EFBIG, "File offset value too large"); + return (int)offs; +} + + +void iobase::open() +{ + cancel(); + chstat(IO_OPENING); + abspos = 0; + cancelled = false; + eof = false; + stmerrno = 0; + clear(deferrormsg); + active = true; + stmbalance++; + bufalloc(); + doopen(); + chstat(IO_OPENED); +} + + +void iobase::close() +{ + if (!active) + return; + stmbalance--; + try + { + if (bufdata != 0 && !cancelled) + flush(); + doclose(); + } + catch(estream* e) + { + delete e; + } + buffree(); + active = false; + eof = true; + chstat(IO_CLOSED); +} + + +void iobase::cancel() +{ + cancelled = true; + close(); +} + + +large iobase::seekx(large newpos, ioseekmode mode) +{ + if (!active) + errstminactive(); + flush(); + large ret = doseek(newpos, mode); + if (ret < 0) + error(ESPIPE, "Seek failed"); + bufclear(); + eof = false; + abspos = ret; + return ret; +} + + +void iobase::flush() +{ +} + + +large iobase::doseek(large newpos, ioseekmode mode) +{ + if (handle == invhandle) + { + error(ESPIPE, "Can't seek on this device"); + return -1; + } +#ifdef WIN32 + static int wmode[3] = {FILE_BEGIN, FILE_CURRENT, FILE_END}; + LARGE_INTEGER li; + li.QuadPart = newpos; + li.LowPart = SetFilePointer(HANDLE(handle), li.LowPart, &li.HighPart, wmode[mode]); + if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) + return -1; + return li.QuadPart; +#else + static int umode[3] = {SEEK_SET, SEEK_CUR, SEEK_END}; + return lseek(handle, newpos, umode[mode]); +#endif +} + + +void iobase::doclose() +{ +#ifdef WIN32 + CloseHandle(HANDLE(pexchange(&handle, invhandle))); +#else + ::close(pexchange(&handle, invhandle)); +#endif +} + + +void iobase::set_active(bool newval) +{ + if (newval != active) + if (newval) + open(); + else + close(); +} + + +void iobase::set_bufsize(int newval) +{ + if (active) + fatal(CRIT_FIRST + 12, "Cannot change buffer size while stream is active"); + if (newval < 0) + bufsize = defbufsize; + else + bufsize = newval; +} + + +string iobase::get_errstmname() +{ + return get_streamname(); +} + + +const char* iobase::uerrmsg(int code) +{ + return unixerrmsg(code); +} + + +int iobase::uerrno() +{ + return unixerrno(); +} + + +string iobase::get_errormsg() +{ + string s = uerrmsg(stmerrno); + if (isempty(s)) + s = deferrormsg; + if (pos('[', s) >= 0 && *(pconst(s) + length(s) - 1) == ']') + return s; + string e = get_errstmname(); + if (isempty(e)) + return s; + return s + " [" + e + ']'; +} + + +#ifdef _MSC_VER +// disable "unreachable code" warning for throw (known compiler bug) +# pragma warning (disable: 4702) +#endif + +void iobase::error(int code, const char* defmsg) +{ + eof = true; + stmerrno = code; + deferrormsg = defmsg; + throw new estream(this, code, get_errormsg()); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pipbase.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pipbase.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,416 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include // for snprintf + +#include "pinet.h" +#ifndef PTYPES_ST +# include "pasync.h" // for mutex +#endif + + +PTYPES_BEGIN + +// +// reentrant gehostby*() mess +// + +#if defined(PTYPES_ST) +# define USE_GETHOSTBY +#else +# if defined(WIN32) || defined(__hpux) +# define USE_GETHOSTBY +# elif defined(__FreeBSD__) || defined(__DARWIN__) +# define USE_GETIPNODEBY +# elif defined(linux) +# define USE_GETHOSTBY_R6 +# elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) +# define USE_LOCKED_GETHOSTBY +# else // hopefully the Sun-style call will work on all other systems as well +# define USE_GETHOSTBY_R5 +# endif +#endif + +#define GETHOSTBY_BUF_SIZE 4096 + + +// +// sockets init/startup +// + +// usockerrno() is used in all socket classes anyway, so this module +// along with the initialization code below will always be linked to +// a networking program + +#ifdef WIN32 + +static class _sock_init +{ +public: + _sock_init(); + ~_sock_init(); +} _init; + + +_sock_init::_sock_init() +{ + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD(2, 0); + + err = WSAStartup(wVersionRequested, &wsaData); + if ( err != 0 ) + fatal(CRIT_FIRST + 50, "WinSock initialization failure"); + + if ( LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0 ) + fatal(CRIT_FIRST + 51, "WinSock version mismatch (2.0 or compatible required)"); +} + + +_sock_init::~_sock_init() +{ + WSACleanup(); +} + +#endif + + + +// +// internet address +// + +ipaddress ipnone = uint(0xffffffff); +ipaddress ipany = INADDR_ANY; +ipaddress ipbcast = INADDR_BROADCAST; + + + +ipaddress::ipaddress(int a, int b, int c, int d) +{ + data[0] = uchar(a); + data[1] = uchar(b); + data[2] = uchar(c); + data[3] = uchar(d); +} + + +// +// peer info +// + + +ippeerinfo::ippeerinfo() + : ip(ipnone), host(), port(0) +{ +} + + +ippeerinfo::ippeerinfo(ipaddress iip, const string& ihost, int iport) + : ip(iip), host(ihost), port(iport) +{ +} + + +ipaddress ippeerinfo::get_ip() +{ + if (ip == ipnone && !isempty(host)) + { + ip = ulong(phostbyname(host)); + if (ip == ipnone) + notfound(); + } + return ip; +} + + +string ippeerinfo::get_host() +{ + if (!isempty(host)) + return host; + + if (ip == ipnone || ip == ipany || ip == ipbcast) + return nullstring; + + host = phostbyaddr(ip); + if (isempty(host)) + notfound(); + + return host; +} + + +void ippeerinfo::clear() +{ + ip = ipnone; + PTYPES_NAMESPACE::clear(host); + port = 0; +} + + +string ippeerinfo::asstring(bool showport) const +{ + string t; + if (!isempty(host)) + t = host; + else if (ip == ipany) + t = '*'; + else if (ip == ipnone) + t = '-'; + else + t = iptostring(ip); + if (showport && port != 0) + t += ':' + itostring(port); + return t; +} + + +// +// internet utilities +// + +int ptdecl usockerrno() +{ +#ifdef WIN32 + return WSAGetLastError(); +#else + return errno; +#endif +} + + +const char* ptdecl usockerrmsg(int code) +{ + switch(code) + { + // only minimal set of most frequent/expressive errors; others go as "I/O error" + case ENOTSOCK: return "Invalid socket descriptor"; + case EMSGSIZE: return "Message too long"; + case ENOPROTOOPT: + case EPROTONOSUPPORT: + // case EPFNOSUPPORT: + case EAFNOSUPPORT: return "Protocol or address family not supported"; + case EADDRINUSE: return "Address already in use"; + case EADDRNOTAVAIL: return "Address not available"; + case ENETDOWN: return "Network is down"; + case ENETUNREACH: return "Network is unreachable"; + case ECONNRESET: return "Connection reset by peer"; + case ETIMEDOUT: return "Operation timed out"; + case ECONNREFUSED: return "Connection refused"; +// case EHOSTDOWN: return "Host is down"; + case EHOSTUNREACH: return "No route to host"; + + // we always translate h_errno to ENOENT and simply show "host not found" + case ENOENT: return "Host not found"; + default: return unixerrmsg(code); + } +} + + +string ptdecl iptostring(ipaddress ip) +{ + char buf[16]; + snprintf(buf, sizeof(buf), "%d.%d.%d.%d", + uint(ip[0]), uint(ip[1]), uint(ip[2]), uint(ip[3])); + return string(buf); +} + + +#if defined(USE_LOCKED_GETHOSTBY) +static mutex hplock; +#endif + + +ipaddress ptdecl phostbyname(const char* name) +{ + ipaddress ip; + hostent* hp; + + if ((ip = ::inet_addr(name)) != ipnone) + { + if (ip[3] == 0) // network address? + return ipnone; + } + else + { +#if defined(USE_GETHOSTBY) + if ((hp = ::gethostbyname(name)) != nil) +#elif defined(USE_LOCKED_GETHOSTBY) + hplock.enter(); + if ((hp = ::gethostbyname(name)) != nil) +#elif defined(USE_GETIPNODEBY) + int herrno; + if ((hp = ::getipnodebyname(name, AF_INET, 0, &herrno)) != nil) +#elif defined(USE_GETHOSTBY_R6) + int herrno; + hostent result; + char buf[GETHOSTBY_BUF_SIZE]; + if ((::gethostbyname_r(name, &result, buf, sizeof(buf), &hp, &herrno) == 0) && hp) +#elif defined(USE_GETHOSTBY_R5) + int herrno; + hostent result; + char buf[GETHOSTBY_BUF_SIZE]; + if ((hp = ::gethostbyname_r(name, &result, buf, sizeof(buf), &herrno)) != nil) +#endif + { + if (hp->h_addrtype == AF_INET) + memcpy(ip.data, hp->h_addr, sizeof(ip.data)); +#ifdef USE_GETIPNODEBY + freehostent(hp); +#endif + } +#if defined(USE_LOCKED_GETHOSTBY) + hplock.leave(); +#endif + } + + return ip; +} + + +string ptdecl phostbyaddr(ipaddress ip) +{ + hostent* hp; + string r; + +#if defined(USE_GETHOSTBY) + if ((hp = ::gethostbyaddr(pconst(ip.data), sizeof(ip.data), AF_INET)) != nil) +#elif defined(USE_LOCKED_GETHOSTBY) + hplock.enter(); + if ((hp = ::gethostbyaddr(pconst(ip.data), sizeof(ip.data), AF_INET)) != nil) +#elif defined(USE_GETIPNODEBY) + int herrno; + if ((hp = ::getipnodebyaddr(pconst(ip.data), sizeof(ip.data), AF_INET, &herrno)) != nil) +#elif defined(USE_GETHOSTBY_R6) + int herrno; + hostent result; + char buf[GETHOSTBY_BUF_SIZE]; + if ((::gethostbyaddr_r(pconst(ip.data), sizeof(ip.data), AF_INET, &result, buf, sizeof(buf), &hp, &herrno) == 0) && hp) +#elif defined(USE_GETHOSTBY_R5) + int herrno; + hostent result; + char buf[GETHOSTBY_BUF_SIZE]; + if ((hp = ::gethostbyaddr_r(pconst(ip.data), sizeof(ip.data), AF_INET, &result, buf, sizeof(buf), &herrno)) != nil) +#endif + { + r = hp->h_name; +#ifdef USE_GETIPNODEBY + freehostent(hp); +#endif + } +#if defined(USE_LOCKED_GETHOSTBY) + hplock.leave(); +#endif + + return r; +} + + +string ptdecl phostcname(const char* name) +{ + hostent* hp; + string r; + +#if defined(USE_GETHOSTBY) + if ((hp = ::gethostbyname(name)) != nil) +#elif defined(USE_LOCKED_GETHOSTBY) + hplock.enter(); + if ((hp = ::gethostbyname(name)) != nil) +#elif defined(USE_GETIPNODEBY) + int herrno; + if ((hp = ::getipnodebyname(name, AF_INET, 0, &herrno)) != nil) +#elif defined(USE_GETHOSTBY_R6) + int herrno; + hostent result; + char buf[GETHOSTBY_BUF_SIZE]; + if ((::gethostbyname_r(name, &result, buf, sizeof(buf), &hp, &herrno) == 0) && hp) +#elif defined(USE_GETHOSTBY_R5) + int herrno; + hostent result; + char buf[GETHOSTBY_BUF_SIZE]; + if ((hp = ::gethostbyname_r(name, &result, buf, sizeof(buf), &herrno)) != nil) +#endif + { + r = hp->h_name; +#ifdef USE_GETIPNODEBY + freehostent(hp); +#endif + } +#if defined(USE_LOCKED_GETHOSTBY) + hplock.leave(); +#endif + + return r; +} + + +bool ptdecl psockwait(int handle, int timeout) +{ +#ifdef _MSC_VER +// disable "condition always true" warning caused by Microsoft's FD_SET macro +# pragma warning (disable: 4127) +#endif + if (handle < 0) + return false; + fd_set readfds; + FD_ZERO(&readfds); + FD_SET((uint)handle, &readfds); + timeval t; + t.tv_sec = timeout / 1000; + t.tv_usec = (timeout % 1000) * 1000; + return ::select(FD_SETSIZE, &readfds, nil, nil, (timeout < 0) ? nil : &t) > 0; +} + + +bool ptdecl psockname(int handle, ippeerinfo& p) +{ + sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + psocklen addrlen = sizeof(sa); + if (getsockname(handle, (sockaddr*)&sa, &addrlen) != 0) + return false; + if (sa.sin_family != AF_INET) + return false; + p.ip = sa.sin_addr.s_addr; + p.port = ntohs(sa.sin_port); + return true; +} + + +#ifdef _MSC_VER +// disable "unreachable code" warning for throw (known compiler bug) +# pragma warning (disable: 4702) +#endif + +void ippeerinfo::notfound() +{ + string t = usockerrmsg(ENOENT); + throw new estream(nil, ENOENT, t + " [" + asstring(false) + ']'); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pipmsg.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pipmsg.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,203 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif + + +#include "pinet.h" + + +PTYPES_BEGIN + + +// +// ipmessage: IPv4 UDP message class +// + + +ipmessage::ipmessage() + : unknown(), ippeerinfo(ipnone, nullstring, 0), handle(invhandle) {} + + +ipmessage::ipmessage(ipaddress iip, int iport) + : unknown(), ippeerinfo(iip, nullstring, iport), handle(invhandle) {} + + +ipmessage::ipmessage(const char* ihost, int iport) + : unknown(), ippeerinfo(ipnone, ihost, iport), handle(invhandle) {} + + +ipmessage::ipmessage(const string& ihost, int iport) + : unknown(), ippeerinfo(ipnone, ihost, iport), handle(invhandle) {} + + +ipmessage::~ipmessage() +{ + close(); +} + + +void ipmessage::set_ip(ipaddress iip) +{ + ip = iip; + PTYPES_NAMESPACE::clear(host); +} + + +void ipmessage::set_host(const string& ihost) +{ + host = ihost; + ip = 0; +} + + +void ipmessage::set_host(const char* ihost) +{ + host = ihost; + ip = 0; +} + + +void ipmessage::set_port(int iport) +{ + port = iport; +} + + +ipaddress ipmessage::get_myip() +{ + ippeerinfo p; + if (!psockname(handle, p)) + error(usockerrno(), "Couldn't get my IP"); + return p.get_ip(); +} + + +int ipmessage::get_myport() +{ + ippeerinfo p; + if (!psockname(handle, p)) + error(usockerrno(), "Couldn't get my port number"); + return p.get_port(); +} + + +void ipmessage::close() +{ + if (handle != invhandle) + ::closesocket(pexchange(&handle, invhandle)); +} + + +void ipmessage::open() +{ + close(); + if ((handle = ::socket(AF_INET, SOCK_DGRAM, 0)) < 0) + error(usockerrno(), "Couldn't create socket"); + // allow broadcasts + int one = 1; + if (::setsockopt(handle, SOL_SOCKET, SO_BROADCAST, (sockval_t)&one, sizeof(one)) != 0) + error(usockerrno(), "Couldn't enable broadcasts"); + sockopt(handle); +} + + +void ipmessage::sockopt(int) +{ +} + + +bool ipmessage::waitfor(int timeout) +{ + return psockwait(handle, timeout); +} + + +void ipmessage::send(const char* buf, int count) +{ + if (handle == invhandle) + open(); + + sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(ushort(get_port())); + sa.sin_addr.s_addr = get_ip(); + if (sendto(handle, buf, count, 0, (sockaddr*)&sa, sizeof(sa)) < 0) + error(usockerrno(), "Couldn't write"); +} + + +int ipmessage::receive(char* buf, int count, ipaddress& src) +{ + if (handle == invhandle) + error(EINVAL, "Couldn't read"); // must send() first + + sockaddr_in sa; + psocklen fromlen = sizeof(sa); + int result = ::recvfrom(handle, buf, count, 0, (sockaddr*)&sa, &fromlen); + if (result < 0) + error(usockerrno(), "Couldn't read"); + src = sa.sin_addr.s_addr; + return result; +} + + +int ipmessage::receive(char* buf, int count) +{ + ipaddress src; + return receive(buf, count, src); +} + + +string ipmessage::receive(int max, ipaddress& src) +{ + string result; + setlength(result, max); + int numread = receive(pchar(pconst(result)), max, src); + setlength(result, numread); + return result; +} + + +string ipmessage::receive(int max) +{ + ipaddress src; + return receive(max, src); +} + + +#ifdef _MSC_VER +// disable "unreachable code" warning for throw (known compiler bug) +# pragma warning (disable: 4702) +#endif + +void ipmessage::error(int code, const char* msg) +{ + string s = usockerrmsg(code); + if (isempty(s)) + s = msg; + throw new estream(nil, code, s + " [" + ippeerinfo::asstring(true) + ']'); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pipmsgsv.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pipmsgsv.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,140 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif + + +#include "pinet.h" + + +PTYPES_BEGIN + + +// +// ipmsgserver: IPv4 UDP socket server +// + + +ipmsgserver::ipmsgserver() + : ipsvbase(SOCK_DGRAM), ippeerinfo(), handle(invhandle) +{ +} + + +ipmsgserver::~ipmsgserver() +{ + close(); +} + + +void ipmsgserver::dobind(ipbindinfo* b) +{ + sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(ushort(b->get_port())); + sa.sin_addr.s_addr = b->get_ip(); + if (::bind(b->handle, (sockaddr*)&sa, sizeof(sa)) != 0) + error(*b, usockerrno(), "Couldn't bind address"); +} + + +void ipmsgserver::close() +{ + if (!active) + return; + ipsvbase::close(); + handle = invhandle; + ippeerinfo::clear(); +} + + +bool ipmsgserver::poll(int i, int timeout) +{ + if (!active) + open(); + return dopoll(&i, timeout); +} + + +int ipmsgserver::receive(char* buf, int count) +{ + if (!active) + open(); + ippeerinfo::clear(); + + // determine which socket has pending data + int i = -1; + if (!dopoll(&i, -1)) + error(*this, EINVAL, "Couldn't read"); + ipbindinfo* b = (ipbindinfo*)addrlist[i]; + handle = b->handle; + + // read data + sockaddr_in sa; + psocklen len = sizeof(sa); + int result = ::recvfrom(handle, buf, count, 0, (sockaddr*)&sa, &len); + if (result < 0) + error(*b, usockerrno(), "Couldn't read"); + + // set up peer ip and port + ip = sa.sin_addr.s_addr; + port = ntohs(sa.sin_port); + return result; +} + + +string ipmsgserver::receive(int max) +{ + string result; + setlength(result, max); + int numread = receive(pchar(pconst(result)), max); + setlength(result, numread); + return result; +} + + +void ipmsgserver::send(const char* buf, int count) +{ + if (!active || handle == invhandle || ip == ipnone) + error(*this, EINVAL, "Couldn't write"); // must receive() first + + sendto(buf, count, get_ip(), get_port()); +} + + +void ipmsgserver::sendto(const char* buf, int count, ipaddress ip, int port) +{ + if (!active || handle == invhandle || ip == ipnone) + error(*this, EINVAL, "Couldn't write"); // must receive() first + + sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(ushort(port)); + sa.sin_addr.s_addr = ip; + if (::sendto(handle, buf, count, 0, (sockaddr*)&sa, sizeof(sa)) < 0) + error(*this, usockerrno(), "Couldn't write"); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pipstm.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pipstm.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,248 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif + + +#include "pinet.h" + + +PTYPES_BEGIN + + +// +// internet (ipv4) socket +// + + +ipstream::ipstream() + : fdxstm(), ippeerinfo(0, nullstring, 0), svsocket(invhandle) {} + + +ipstream::ipstream(ipaddress iip, int iport) + : fdxstm(), ippeerinfo(iip, nullstring, iport), svsocket(invhandle) {} + + +ipstream::ipstream(const char* ihost, int iport) + : fdxstm(), ippeerinfo(ipnone, ihost, iport), svsocket(invhandle) {} + + +ipstream::ipstream(const string& ihost, int iport) + : fdxstm(), ippeerinfo(ipnone, ihost, iport), svsocket(invhandle) {} + + +ipstream::~ipstream() +{ + cancel(); +} + + +int ipstream::classid() +{ + return CLASS3_IPSTM; +} + + +int ipstream::uerrno() +{ + return usockerrno(); +} + + +const char* ipstream::uerrmsg(int code) +{ + return usockerrmsg(code); +} + + +string ipstream::get_streamname() +{ + return ippeerinfo::asstring(true); +} + + +void ipstream::set_ip(ipaddress iip) +{ + close(); + ip = iip; + PTYPES_NAMESPACE::clear(host); +} + + +void ipstream::set_host(const string& ihost) +{ + close(); + host = ihost; + ip = ipnone; +} + + +void ipstream::set_host(const char* ihost) +{ + close(); + host = ihost; + ip = ipnone; +} + + +void ipstream::set_port(int iport) +{ + close(); + port = iport; +} + + +void ipstream::doopen() +{ + sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + + if (svsocket != invhandle) + { + psocklen addrlen = sizeof(sa); + + // open an active server socket and assign ip and host fields + chstat(IO_CONNECTING); + + // the last parameter of accept() can be either int* or uint* + // depending on the target platform :( + if ((handle = ::accept(svsocket, (sockaddr*)&sa, &addrlen)) < 0) + error(uerrno(), "Couldn't create socket"); + chstat(IO_CONNECTED); + + if (sa.sin_family != AF_INET) + error(EAFNOSUPPORT, "Address family not supported"); + + PTYPES_NAMESPACE::clear(host); + ip = sa.sin_addr.s_addr; + port = ntohs(sa.sin_port); + } + + else + { + sa.sin_family = AF_INET; + sa.sin_port = htons(ushort(get_port())); + + chstat(IO_RESOLVING); + sa.sin_addr.s_addr = get_ip(); // force to resolve the address if needed + chstat(IO_RESOLVED); + + // open a client socket + if ((handle = ::socket(sa.sin_family, SOCK_STREAM, 0)) < 0) + error(uerrno(), "Couldn't create socket"); + + // a chance to set up extra socket options + sockopt(handle); + + chstat(IO_CONNECTING); + if (::connect(handle, (sockaddr*)&sa, sizeof(sa)) < 0) + { + int e = uerrno(); + closehandle(); + error(e, "Couldn't connect to remote host"); + } + chstat(IO_CONNECTED); + } +} + + +void ipstream::sockopt(int) +{ +} + + +void ipstream::closehandle() +{ + ::closesocket(pexchange(&handle, invhandle)); +} + + +large ipstream::doseek(large, ioseekmode) +{ + return -1; +} + + +void ipstream::doclose() +{ + svsocket = invhandle; + if (!cancelled) + ::shutdown(handle, SHUT_RDWR); + closehandle(); +} + + +#ifdef WIN32 + +int ipstream::dorawread(char* buf, int count) +{ + int ret; + if ((ret = ::recv(handle, buf, count, 0)) == -1) + error(uerrno(), "Couldn't read"); + return ret; +} + + +int ipstream::dorawwrite(const char* buf, int count) +{ + int ret; + if ((ret = ::send(handle, buf, count, 0)) == -1) + error(uerrno(), "Couldn't write"); + return ret; +} + +#endif + + +bool ipstream::waitfor(int timeout) +{ + if (!active) + errstminactive(); + if (bufsize > 0 && bufend > bufpos) + return true; + return psockwait(handle, timeout); +} + + +ipaddress ipstream::get_myip() +{ + if (!active) + errstminactive(); + ippeerinfo p; + if (!psockname(handle, p)) + error(uerrno(), "Couldn't get my IP"); + return p.get_ip(); +} + + +int ipstream::get_myport() +{ + if (!active) + errstminactive(); + ippeerinfo p; + if (!psockname(handle, p)) + error(uerrno(), "Couldn't get my port number"); + return p.get_port(); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pipstmsv.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pipstmsv.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,101 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif + + +#include "pinet.h" + + +PTYPES_BEGIN + + +// +// ipstmserver +// + + +ipstmserver::ipstmserver() + : ipsvbase(SOCK_STREAM) +{ +} + + +ipstmserver::~ipstmserver() +{ + close(); +} + + +void ipstmserver::dobind(ipbindinfo* b) +{ +#ifndef WIN32 + // set SO_REAUSEADDR to true, unix only. on windows this option causes + // the previous owner of the socket to give up, which is not desirable + // in most cases, neither compatible with unix. + int one = 1; + if (::setsockopt(b->handle, SOL_SOCKET, SO_REUSEADDR, + (sockval_t)&one, sizeof(one)) != 0) + error(*b, usockerrno(), "Can't reuse local address"); +#endif + + // set up sockaddr_in and try to bind it to the socket + sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(ushort(b->get_port())); + sa.sin_addr.s_addr = b->get_ip(); + + if (::bind(b->handle, (sockaddr*)&sa, sizeof(sa)) != 0) + error(*b, usockerrno(), "Couldn't bind address"); + + if (::listen(b->handle, SOMAXCONN) != 0) + error(*b, usockerrno(), "Couldn't listen on socket"); +} + + +bool ipstmserver::poll(int i, int timeout) +{ + if (!active) + open(); + return dopoll(&i, timeout); +} + + +bool ipstmserver::serve(ipstream& client, int i, int timeout) +{ + if (!active) + open(); + + client.cancel(); + if (dopoll(&i, timeout)) + { + // connect the ipstream object to the client requesting the connection + client.svsocket = get_addr(i).handle; + client.open(); + return true; + } + return false; +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pipsvbase.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pipsvbase.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,177 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "pinet.h" + + +PTYPES_BEGIN + + +// +// ipbindinfo +// + + +ipbindinfo::ipbindinfo(ipaddress iip, const string& ihost, int iport) + : unknown(), ippeerinfo(iip, ihost, iport), handle(invhandle) +{ +} + + +ipbindinfo::~ipbindinfo() +{ +} + + +// +// ipsvbase +// + + +ipsvbase::ipsvbase(int isocktype) + : socktype(isocktype), active(false), addrlist(true) {} + + +ipsvbase::~ipsvbase() +{ + close(); +} + + +void ipsvbase::error(ippeerinfo& p, int code, const char* defmsg) +{ + string msg = usockerrmsg(code); + if (isempty(msg)) + msg = defmsg; + msg += " [" + p.asstring(true) + ']'; + throw new estream(nil, code, msg); +} + + +int ipsvbase::bind(ipaddress ip, int port) +{ + close(); + addrlist.add(new ipbindinfo(ip, nullstring, port)); + return addrlist.get_count() - 1; +} + + +int ipsvbase::bindall(int port) +{ + close(); + return bind(ipany, port); +} + + +void ipsvbase::clear() +{ + close(); + addrlist.clear(); +} + + +void ipsvbase::open() +{ + close(); + if (addrlist.get_count() == 0) + fatal(CRIT_FIRST + 52, "No addresses specified to bind to"); + active = true; + for (int i = 0; i < addrlist.get_count(); i++) + { + ipbindinfo* b = addrlist[i]; + b->handle = ::socket(AF_INET, socktype, 0); + if (b->handle < 0) + error(*b, usockerrno(), "Couldn't create socket"); + sockopt(b->handle); + dobind(b); + } +} + + +void ipsvbase::close() +{ + if (!active) + return; + for (int i = 0; i < addrlist.get_count(); i++) + { + ipbindinfo* b = addrlist[i]; + ::closesocket(pexchange(&b->handle, invhandle)); + } + active = false; +} + + +bool ipsvbase::dopoll(int* i, int timeout) +{ + fd_set set; + setupfds(&set, *i); + timeval t; + t.tv_sec = timeout / 1000; + t.tv_usec = (timeout % 1000) * 1000; + if (::select(FD_SETSIZE, &set, nil, nil, (timeout < 0) ? nil : &t) > 0) + { + if (*i >= 0) + return true; + // if the user selected -1 (all), find the socket which has a pending connection + // and assign it to i + for (int j = 0; j < addrlist.get_count(); j++) + if (FD_ISSET(uint(addrlist[j]->handle), &set)) + { + *i = j; + return true; + } + } + return false; +} + + +void ipsvbase::setupfds(void* set, int i) +{ +#ifdef _MSC_VER +// disable "condition always true" warning caused by Microsoft's FD_SET macro +# pragma warning (disable: 4127) +#endif + FD_ZERO((fd_set*)set); + if (i >= 0) + { + int h = get_addr(i).handle; + if (h >= 0) + FD_SET((uint)h, (fd_set*)set); + } + else + for (i = 0; i < addrlist.get_count(); i++) + { + int h = addrlist[i]->handle; + if (h >= 0) + FD_SET((uint)h, (fd_set*)set); + } +} + + +void ipsvbase::sockopt(int) +{ +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pmd5.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pmd5.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,517 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +/* + * Derived from L. Peter Deutsch's independent implementation + * of MD5 (RFC1321). The original copyright notice follows. + * This file is a concatenation of the original md5.h and + * md5.c and contains PTypes' MD5 wrapper class at the bottom. + */ + +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ + +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + + +#include + +#include "pstreams.h" + + +PTYPES_BEGIN + + +// +// --- md5.h --------------------------------------------------------------- +// + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + + +// +// typedef unsigned char md5_byte_t; /* 8-bit byte */ +// typedef unsigned int md5_word_t; /* 32-bit word */ +// +// /* Define the state of the MD5 Algorithm. */ +// 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; +// + +/* Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + + +// +// --- md5.c --------------------------------------------------------------- +// + + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} + + + +// +// --- PTypes' wrapper class ----------------------------------------------- +// + + +outmd5::outmd5(outstm* istm): outfilter(istm, 0) +{ + memset(&ctx, 0, sizeof ctx); + memset(digest, 0, sizeof digest); +} + + +outmd5::~outmd5() +{ + close(); +} + + +void outmd5::doopen() +{ + outfilter::doopen(); + memset(digest, 0, sizeof digest); + md5_init(&ctx); +} + + +void outmd5::doclose() +{ + md5_finish(&ctx, (unsigned char*)digest); + outfilter::doclose(); +} + + +int outmd5::dorawwrite(const char* buf, int count) +{ + if (count > 0) + { + md5_append(&ctx, (const unsigned char*)buf, (unsigned)count); + if (stm != nil) + stm->write(buf, count); + return count; + } + else + return 0; +} + + +string outmd5::get_streamname() +{ + return "MD5"; +} + + +string outmd5::get_digest() +{ + close(); + string result; + // the first 120 bits are divided into 24-bit portions; + // each portion is represented with 4 characters from the base64 set + for (int i = 0; i <= 12; i += 3) + { + long v = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2]; + result += itostring(large(v), 64, 4); + } + // the last byte is complemented with 4 zero bits to form + // the last two base64 characters + return result + itostring(large(digest[15] << 4), 64, 2); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pmem.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pmem.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,86 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include + +#include "pport.h" + + +PTYPES_BEGIN + + +const int quant = 64; +const int qmask = ~63; +const int quant2 = 4096; +const int qmask2 = ~4095; + +// dynamic reallocation policy for strings and lists + +int ptdecl memquantize(int a) +{ + if (a <= 16) + return 16; + if (a <= 32) + return 32; + else if (a <= 2048) + return (a + quant - 1) & qmask; + else + return (a + quant2 - 1) & qmask2; +} + + +void ptdecl memerror() +{ + fatal(CRIT_FIRST + 5, "Not enough memory"); +} + + +void* ptdecl memalloc(uint a) +{ + if (a == 0) + return nil; + else + { + void* p = malloc(a); + if (p == nil) + memerror(); + return p; + } +} + + +void* ptdecl memrealloc(void* p, uint a) +{ + if (a == 0) + { + memfree(p); + return nil; + } + else if (p == nil) + return memalloc(a); + else + { + p = realloc(p, a); + if (p == nil) + memerror(); + return p; + } +} + + +void ptdecl memfree(void* p) +{ + if (p != nil) + free(p); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pmsgq.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pmsgq.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,282 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "pasync.h" + + +PTYPES_BEGIN + + +static void msgerror() +{ + fatal(CRIT_FIRST + 42, "Invalid message object"); +} + + +message::message(int iid, pintptr iparam) + : next(nil), sync(nil), id(iid), param(iparam), result(0) +{ +} + + +message::~message() +{ +} + + +jobqueue::jobqueue(int ilimit) + : limit(ilimit), head(nil), tail(nil), qcount(0), sem(0), ovrsem(ilimit), qlock() +{ +} + + +jobqueue::~jobqueue() +{ + purgequeue(); +} + + +bool jobqueue::enqueue(message* msg, int timeout) +{ + if (msg == nil) + msgerror(); + + if (!ovrsem.wait(timeout)) + return false; + qlock.enter(); + msg->next = nil; + if (head != nil) + head->next = msg; + head = msg; + if (tail == nil) + tail = msg; + qcount++; + qlock.leave(); + sem.post(); + return true; +} + + +bool jobqueue::push(message* msg, int timeout) +{ + if (msg == nil) + msgerror(); + + if (!ovrsem.wait(timeout)) + return false; + qlock.enter(); + msg->next = tail; + tail = msg; + if (head == nil) + head = msg; + qcount++; + qlock.leave(); + sem.post(); + return true; +} + + +message* jobqueue::dequeue(bool safe, int timeout) +{ + if (!sem.wait(timeout)) + return nil; + if (safe) + qlock.enter(); + message* msg = tail; + tail = msg->next; + qcount--; + if (tail == nil) + head = nil; + if (safe) + qlock.leave(); + ovrsem.post(); + return msg; +} + + +void jobqueue::purgequeue() +{ + qlock.enter(); + while (get_count() > 0) + delete dequeue(false); + qlock.leave(); +} + + +bool jobqueue::post(message* msg, int timeout) +{ + return enqueue(msg, timeout); +} + + +bool jobqueue::post(int id, pintptr param, int timeout) +{ + return post(new message(id, param), timeout); +} + + +bool jobqueue::posturgent(message* msg, int timeout) +{ + return push(msg, timeout); +} + + +bool jobqueue::posturgent(int id, pintptr param, int timeout) +{ + return posturgent(new message(id, param), timeout); +} + + +message* jobqueue::getmessage(int timeout) +{ + return dequeue(true, timeout); +} + + +msgqueue::msgqueue(int ilimit) + : jobqueue(ilimit), thrlock(), owner(0), quit(false) +{ +} + + +msgqueue::~msgqueue() +{ +} + + +void msgqueue::takeownership() +{ + if (owner != pthrself()) + { + thrlock.enter(); // lock forever +// if (owner != 0) +// fatal(CRIT_FIRST + 45, "Ownership of the message queue already taken"); + owner = pthrself(); + } +} + + +pintptr msgqueue::finishmsg(message* msg) +{ + if (msg != nil) + { + pintptr result = msg->result; + + // if the message was sent by send(), + // just signale the semaphore + if (msg->sync != nil) + msg->sync->post(); + + // otherwise finish it + else + delete msg; + + return result; + } + else + return 0; +} + + +pintptr msgqueue::send(message* msg) +{ + if (msg == nil) + msgerror(); + + try + { + // if we are in the main thread, + // immediately handle the msg + if (pthrequal(owner)) + handlemsg(msg); + + // if this is called from a concurrent thread, + // sync through a semaphore + else + { + if (msg->sync != nil) + msgerror(); + semaphore sync(0); + msg->sync = &sync; + push(msg); + msg->sync->wait(); + msg->sync = 0; + } + } + catch (...) + { + finishmsg(msg); + throw; + } + + return finishmsg(msg); +} + + +pintptr msgqueue::send(int id, pintptr param) +{ + return send(new message(id, param)); +} + + +void msgqueue::processone() +{ + takeownership(); + message* msg = dequeue(); + try + { + handlemsg(msg); + } + catch(...) + { + finishmsg(msg); + throw; + } + finishmsg(msg); +} + + +void msgqueue::processmsgs() +{ + while (!quit && get_count() > 0) + processone(); +} + + +void msgqueue::run() +{ + quit = false; + do + { + processone(); + } + while (!quit); +} + + +void msgqueue::handlemsg(message* msg) +{ + msghandler(*msg); +} + + +void msgqueue::defhandler(message& msg) +{ + switch(msg.id) + { + case MSG_QUIT: + quit = true; + break; + } +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pmtxtable.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pmtxtable.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,42 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + + +#include "pasync.h" + + +PTYPES_BEGIN + + +pmemlock _mtxtable[_MUTEX_HASH_SIZE] // currently 29 +#ifndef WIN32 + = { + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT, _MTX_INIT, + _MTX_INIT +} +#endif +; + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pnpipe.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pnpipe.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,290 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +# include +# include +#endif + +#include "pstreams.h" + + +PTYPES_BEGIN + + +#ifdef WIN32 + +string ptdecl namedpipe::realpipename(const string& pipename, const string& svrname) +{ + if (isempty(pipename)) + return nullstring; + string realname = pipename; + if (*pconst(pipename) == '/') + { + int i = rpos('/', realname); + del(realname, 0, i + 1); + } + string s; + if (isempty(svrname)) + s = '.'; + else + s = svrname; + return "\\\\" + s + "\\pipe\\" + realname; +} + + +#else + +string ptdecl namedpipe::realpipename(const string& pipename) +{ + if (isempty(pipename)) + return nullstring; + if (*pconst(pipename) == '/') + return pipename; + else + return DEF_NAMED_PIPES_DIR + pipename; +} + + +bool namedpipe::setupsockaddr(const string& pipename, void* isa) +{ + sockaddr_un* sa = (sockaddr_un*)isa; + memset(sa, 0, sizeof(sockaddr_un)); + sa->sun_family = AF_UNIX; +#ifdef __FreeBSD__ + sa->sun_len = length(pipename); +#endif + + // copy the path name into the sockaddr structure, 108 chars max (?) + if (length(pipename) + 1 > (int)sizeof(sa->sun_path)) + return false; + strcpy(sa->sun_path, pipename); + return true; +} + +#endif + + +namedpipe::namedpipe() + : fdxstm(), pipename(), svhandle(invhandle) +{ + initovr(); +} + + +namedpipe::namedpipe(const string& ipipename) + : fdxstm(), pipename(), svhandle(invhandle) +{ + pipename = realpipename(ipipename); + initovr(); +} + + +#ifdef WIN32 + +namedpipe::namedpipe(const string& ipipename, const string& servername) + : fdxstm(), pipename(), svhandle(invhandle) +{ + pipename = realpipename(ipipename, servername); + initovr(); +} + + +void namedpipe::initovr() +{ + ovr.hEvent = CreateEvent(0, false, false, 0); +} + + +#endif + + +namedpipe::~namedpipe() +{ + cancel(); +#ifdef WIN32 + CloseHandle(ovr.hEvent); +#endif +} + + +int namedpipe::classid() +{ + return CLASS3_NPIPE; +} + + +string namedpipe::get_streamname() +{ + return pipename; +} + + +void namedpipe::set_pipename(const string& newvalue) +{ + close(); + pipename = realpipename(newvalue); +} + + +void namedpipe::set_pipename(const char* newvalue) +{ + close(); + pipename = realpipename(newvalue); +} + + +large namedpipe::doseek(large, ioseekmode) +{ + return -1; +} + + +void namedpipe::doopen() +{ + +#ifdef WIN32 + + if (svhandle != invhandle) + handle = svhandle; + else + { + int tries = DEF_PIPE_OPEN_RETRY; + int delay = DEF_PIPE_OPEN_TIMEOUT / 2; +retry: + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + handle = int(CreateFile(pipename, GENERIC_READ | GENERIC_WRITE, + 0, &sa, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0)); + if (handle == invhandle) + { + if (GetLastError() == ERROR_PIPE_BUSY) + { + if (--tries > 0) + { + delay *= 2; + Sleep(delay); + goto retry; + } + else + error(EIO, "Pipe busy"); + } + else + error(uerrno(), "Couldn't open named pipe"); + } + } + +#else + if (svhandle != invhandle) + { + if ((handle = ::accept(svhandle, 0, 0)) < 0) + error(uerrno(), "Couldn't create local socket"); + } + + else + { + sockaddr_un sa; + if (!setupsockaddr(pipename, &sa)) + error(ERANGE, "Socket name too long"); + + // cteate a client socket + if ((handle = ::socket(sa.sun_family, SOCK_STREAM, 0)) < 0) + error(uerrno(), "Couldn't create local socket"); + + // ... and connect to the local socket + if (::connect(handle, (sockaddr*)&sa, sizeof(sa)) < 0) + { + int e = uerrno(); + doclose(); + error(e, "Couldn't connect to local socket"); + } + } + +#endif +} + + +#ifdef WIN32 + +int namedpipe::dorawread(char* buf, int count) +{ + unsigned long ret = uint(-1); + ovr.Offset = 0; + ovr.OffsetHigh = 0; + if (!ReadFile(HANDLE(handle), buf, count, &ret, &ovr)) + { + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(ovr.hEvent, DEF_PIPE_TIMEOUT) == WAIT_TIMEOUT) + error(EIO, "Timed out"); + if (!GetOverlappedResult(HANDLE(handle), &ovr, &ret, false)) + error(uerrno(), "Couldn't read"); + } + else + error(uerrno(), "Couldn't read"); + } + return ret; +} + + +int namedpipe::dorawwrite(const char* buf, int count) +{ + unsigned long ret = uint(-1); + ovr.Offset = 0; + ovr.OffsetHigh = 0; + if (!WriteFile(HANDLE(handle), buf, count, &ret, &ovr)) + { + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(ovr.hEvent, DEF_PIPE_TIMEOUT) == WAIT_TIMEOUT) + error(EIO, "Timed out"); + if (!GetOverlappedResult(HANDLE(handle), &ovr, &ret, false)) + error(uerrno(), "Couldn't write"); + } + else + error(uerrno(), "Couldn't write"); + } + return ret; +} + + +#endif + + +void namedpipe::doclose() +{ +#ifdef WIN32 + if (svhandle != invhandle) + DisconnectNamedPipe(HANDLE(handle)); +#endif + svhandle = invhandle; + fdxstm::doclose(); +} + + +void namedpipe::flush() +{ +#ifdef WIN32 + if (!cancelled) + FlushFileBuffers(HANDLE(handle)); +#endif + fdxstm::flush(); +} + + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pnpserver.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pnpserver.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,185 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +# include +# include +# include +# include +#endif + +#include "pstreams.h" + + +PTYPES_BEGIN + + +npserver::npserver(const string& ipipename) + : pipename(), handle(invhandle), active(false) +{ + pipename = namedpipe::realpipename(ipipename); +} + + +npserver::~npserver() +{ + close(); +} + + +void npserver::error(int code, const char* defmsg) +{ + string msg = unixerrmsg(code); + if (isempty(msg)) + msg = defmsg; + msg += " [" + pipename + ']'; + throw new estream(nil, code, msg); +} + + +#ifdef WIN32 + +void npserver::openinst() +{ + // called once at startup and then again, after + // each client connection. strange logic, to say the least... + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + handle = (int)CreateNamedPipe(pipename, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + DEF_PIPE_SYSTEM_BUF_SIZE, DEF_PIPE_SYSTEM_BUF_SIZE, + DEF_PIPE_TIMEOUT, &sa); + + if (handle == invhandle) + error(unixerrno(), "Couldn't create"); +} + + +void npserver::closeinst() +{ + CloseHandle(HANDLE(pexchange(&handle, invhandle))); +} + +#endif + + +void npserver::open() +{ + close(); + +#ifdef WIN32 + + openinst(); + +#else + + sockaddr_un sa; + if (!namedpipe::setupsockaddr(pipename, &sa)) + error(ERANGE, "Socket name too long"); + + if ((handle = ::socket(sa.sun_family, SOCK_STREAM, 0)) < 0) + error(unixerrno(), "Couldn't create local socket"); + + unlink(pipename); + if (::bind(handle, (sockaddr*)&sa, sizeof(sa)) != 0) + error(unixerrno(), "Couldn't bind local socket"); + + if (::listen(handle, SOMAXCONN) != 0) + error(unixerrno(), "Couldn't listen on local socket"); + +#endif + + active = true; +} + + +void npserver::close() +{ + if (active) + { + active = false; +#ifdef WIN32 + closeinst(); +#else + ::close(pexchange(&handle, invhandle)); + unlink(pipename); +#endif + } +} + + +bool npserver::serve(namedpipe& client, int timeout) +{ + if (!active) + open(); + + client.cancel(); + +#ifdef WIN32 + + client.ovr.Offset = 0; + client.ovr.OffsetHigh = 0; + bool result = ConnectNamedPipe(HANDLE(handle), &client.ovr) ? + true : (GetLastError() == ERROR_PIPE_CONNECTED); + + if (!result && GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(client.ovr.hEvent, timeout) == WAIT_TIMEOUT) + return false; + unsigned long ret; + if (!GetOverlappedResult(HANDLE(handle), &client.ovr, &ret, false)) + error(unixerrno(), "Couldn't read"); + result = true; + } + + if (result) + { + client.svhandle = handle; + client.pipename = pipename; + openinst(); + client.open(); + return true; + } + else + error(unixerrno(), "Couldn't connect to client"); + + return false; + +#else + + fd_set set; + FD_ZERO(&set); + FD_SET((uint)handle, &set); + timeval t; + t.tv_sec = timeout / 1000; + t.tv_usec = (timeout % 1000) * 1000; + if (::select(FD_SETSIZE, &set, nil, nil, (timeout < 0) ? nil : &t) > 0) + { + client.svhandle = handle; + client.pipename = pipename; + client.open(); + return true; + } + return false; + +#endif +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pobjlist.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pobjlist.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,156 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "ptypes.h" + + +PTYPES_BEGIN + + +_objlist::_objlist() + : tpodlist() +{ + memset(&config, 0, sizeof(config)); +} + + +_objlist::_objlist(bool ownobjects) + : tpodlist() +{ + memset(&config, 0, sizeof(config)); + config.ownobjects = ownobjects; +} + + +_objlist::~_objlist() +{ +} + + +void _objlist::dofree(void*) +{ + fatal(CRIT_FIRST + 38, "ptrlist::dofree() not defined"); +} + + +int _objlist::compare(const void*, const void*) const +{ + fatal(CRIT_FIRST + 38, "ptrlist::compare() not defined"); + return 0; +} + + +void _objlist::dofree(int index, int num) +{ + void** p = (void**)list + index; + while (--num >= 0) + dofree(*p++); +} + + +void _objlist::doput(int index, void* obj) +{ + void** p = (void**)list + index; + if (config.ownobjects) + dofree(*p); + *p = obj; +} + + +void _objlist::dodel(int index) +{ + if (config.ownobjects) + dofree(doget(index)); + tpodlist::dodel(index); +} + + +void _objlist::dodel(int index, int delcount) +{ + if (config.ownobjects) + { + if (index + delcount > count) + delcount = count - index; + dofree(index, delcount); + } + tpodlist::dodel(index, delcount); +} + + +void _objlist::set_count(int newcount) +{ + if (newcount < count && config.ownobjects) + { + if (newcount < 0) + newcount = 0; + dofree(newcount, count - newcount); + } + _podlist::set_count(newcount, true); +} + + +void* _objlist::dopop() +{ + void* t = doget(--count); + if (count == 0) + set_capacity(0); + return t; +} + + +bool _objlist::search(const void* key, int& index) const +{ + int l, h, i, c; + bool ret = false; + l = 0; + h = count - 1; + while (l <= h) + { + i = (l + h) / 2; + c = compare(key, doget(i)); + if (c > 0) + l = i + 1; + else + { + h = i - 1; + if (c == 0) + { + ret = true; + if (!config.duplicates) + l = i; + } + } + } + index = l; + return ret; +} + + +int _objlist::indexof(void* obj) const +{ + for (int i = 0; i < count; i++) + if (doget(i) == obj) + return i; + return -1; +} + + +#ifdef PTYPES19_COMPAT + +objlist::objlist(bool ownobjects): tobjlist(ownobjects) {} + +objlist::~objlist() {} + +#endif + + +PTYPES_END + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/poutfile.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/poutfile.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,111 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "errno.h" + +#ifdef WIN32 +# include +#else +# include +# include +#endif + +#include "pstreams.h" + + +PTYPES_BEGIN + + +// *BSD hack +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif + + +outfile::outfile() + : outstm(), filename(), syshandle(invhandle), peerhandle(invhandle), + umode(0644), append(false) {} + + +outfile::outfile(const char* ifn, bool iappend) + : outstm(), filename(ifn), syshandle(invhandle), peerhandle(invhandle), + umode(0644), append(iappend) {} + + +outfile::outfile(string const& ifn, bool iappend) + : outstm(), filename(ifn), syshandle(invhandle), peerhandle(invhandle), + umode(0644), append(iappend) {} + + +outfile::~outfile() +{ + close(); +} + + +int outfile::classid() +{ + return CLASS2_OUTFILE; +} + + +string outfile::get_streamname() +{ + return filename; +} + + +void outfile::doopen() +{ + if (syshandle != invhandle) + handle = syshandle; + else + { +#ifdef WIN32 + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + handle = int(CreateFile(filename, GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, + (append ? OPEN_ALWAYS : CREATE_ALWAYS), 0, 0)); +#else + handle = ::open(filename, + O_WRONLY | O_CREAT | O_LARGEFILE | (append ? 0 : O_TRUNC), umode); +#endif + if (handle == invhandle) + error(uerrno(), "Couldn't open"); + if (append) + if (doseek(0, IO_END) == -1) + error(uerrno(), "Couldn't seek to end of file"); + } +} + + +void outfile::flush() +{ + outstm::flush(); +#ifdef WIN32 + FlushFileBuffers(HANDLE(handle)); +#endif +} + + +void outfile::doclose() +{ + outstm::doclose(); + syshandle = invhandle; + peerhandle = invhandle; +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/poutfilter.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/poutfilter.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,77 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include + +#include "pstreams.h" + + +PTYPES_BEGIN + + +outfilter::outfilter(outstm* istm, int ibufsize) +: outstm(false, ibufsize), stm(istm) +{ + if (stm != nil) + stm->addnotification(this); +} + + +outfilter::~outfilter() +{ + if (stm != nil) + stm->delnotification(this); +} + + +void outfilter::freenotify(component* sender) +{ + if (sender == stm) + { + stm = nil; + close(); + } +} + + +void outfilter::doopen() +{ + if (stm != nil && !stm->get_active()) + stm->open(); +} + + +void outfilter::doclose() +{ +} + + +string outfilter::get_errstmname() +{ + if (stm == nil) + return get_streamname(); + else + return get_streamname() + ": " + stm->get_errstmname(); +} + + +void outfilter::set_stm(outstm* istm) +{ + close(); + if (stm != nil) + stm->delnotification(this); + stm = istm; + if (stm != nil) + stm->addnotification(this); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/poutmem.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/poutmem.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,104 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "pstreams.h" + + +PTYPES_BEGIN + + +outmemory::outmemory(int ilimit) + : outstm(false, 0), mem(), limit(ilimit) +{ +} + + +outmemory::~outmemory() +{ + close(); +} + + +int outmemory::classid() +{ + return CLASS2_OUTMEMORY; +} + + +void outmemory::doopen() +{ +} + + +void outmemory::doclose() +{ + clear(mem); +} + + +large outmemory::doseek(large newpos, ioseekmode mode) +{ + large pos; + + switch (mode) + { + case IO_BEGIN: + pos = newpos; + break; + case IO_CURRENT: + pos = abspos + newpos; + break; + default: // case IO_END: + pos = length(mem) + newpos; + break; + } + + if (limit >= 0 && pos > limit) + pos = limit; + + return pos; +} + + +int outmemory::dorawwrite(const char* buf, int count) +{ + if (count <= 0) + return 0; + if (limit >= 0 && abspos + count > limit) + { + count = limit - (int)abspos; + if (count <= 0) + return 0; + } + + // the string reallocator takes care of efficiency + if ((int)abspos + count > length(mem)) + setlength(mem, (int)abspos + count); + memcpy(pchar(pconst(mem)) + (int)abspos, buf, count); + return count; +} + + +string outmemory::get_streamname() +{ + return "mem"; +} + + +string outmemory::get_strdata() +{ + if (!active) + errstminactive(); + return mem; +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/poutstm.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/poutstm.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,215 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include + +#ifdef WIN32 +# include +#else +# include +#endif + +#include "pstreams.h" + + +PTYPES_BEGIN + + +outstm::outstm(bool iflusheol, int ibufsize) + : iobase(ibufsize), flusheol(iflusheol) {} + + +outstm::~outstm() +{ +} + + +int outstm::classid() +{ + return CLASS_OUTSTM; +} + + +int outstm::dorawwrite(const char* buf, int count) +{ + if (handle == invhandle) + return -1; +#ifdef WIN32 + unsigned long ret; + if (!WriteFile(HANDLE(handle), buf, count, &ret, nil)) + { + error(uerrno(), "Couldn't write"); + ret = uint(-1); + } +#else + int ret; + if ((ret = ::write(handle, buf, count)) < 0) + error(uerrno(), "Couldn't write"); +#endif + return ret; +} + + +int outstm::rawwrite(const char* buf, int count) +{ + if (!active) + errstminactive(); + try + { + int ret = dorawwrite(buf, count); + if (ret < 0) + ret = 0; + else + abspos += ret; + chstat(IO_WRITING); + if (ret < count) + { + eof = true; + chstat(IO_EOF); + } + return ret; + } + catch (estream*) + { + eof = true; + chstat(IO_EOF); + throw; + } +} + + +void outstm::bufvalidate() +{ + if (!active) + errstminactive(); + if (bufend > 0) + rawwrite(bufdata, bufend); + bufclear(); +} + + +large outstm::seekx(large newpos, ioseekmode mode) +{ + if (bufdata != 0 && mode != IO_END) + { + large pos; + if (mode == IO_BEGIN) + pos = newpos; + else + pos = tellx() + newpos; + pos -= abspos; + if (pos >= 0 && pos <= bufpos) + { + bufpos = (int)pos; + eof = false; + return tellx(); + } + } + return iobase::seekx(newpos, mode); +} + + +bool outstm::canwrite() +{ + if (bufdata != 0 && bufpos >= bufsize) + { + bufvalidate(); + return bufend < bufsize; + } + else + return true; +} + + +void outstm::flush() +{ + if (bufdata != 0 && stmerrno == 0) + bufvalidate(); +} + + +void outstm::put(char c) +{ + if (!active) + errstminactive(); + if (bufdata == 0) + rawwrite(&c, 1); + else if (canwrite()) + { + bufdata[bufpos] = c; + bufadvance(1); + if (c == 10 && flusheol) + flush(); + } +} + + +int outstm::write(const void* buf, int count) +{ + if (!active) + errstminactive(); + int ret = 0; + if (bufdata == 0) + ret = rawwrite(pconst(buf), count); + else + { + while (count > 0 && canwrite()) + { + int n = imin(count, bufsize - bufpos); + memcpy(bufdata + bufpos, buf, n); + ret += n; + count -= n; + buf = pconst(buf) + n; + bufadvance(n); + } + } + + return ret; +} + + +void outstm::put(const char* str) +{ + if (str != nil) + write(str, hstrlen(str)); +} + + +void outstm::put(const string& str) +{ + write(pconst(str), length(str)); +} + + +void outstm::putline(const char* s) +{ + put(s); + puteol(); +} + + +void outstm::putline(const string& s) +{ + put(s); + puteol(); +} + + +void outstm::puteol() +{ +#ifdef WIN32 + put(13); +#endif + put(10); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/ppipe.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ppipe.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,51 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +#endif + +#include "pstreams.h" + + +PTYPES_BEGIN + + +void infile::pipe(outfile& out) +{ +#ifdef WIN32 + + SECURITY_ATTRIBUTES sa; + HANDLE h[2]; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&h[0], &h[1], &sa, 0)) +#else + int h[2]; + if (::pipe(h) != 0) +#endif + error(uerrno(), "Couldn't create a local pipe"); + + set_syshandle(int(h[0])); + peerhandle = int(h[1]); + out.set_syshandle(int(h[1])); + out.peerhandle = int(h[0]); + open(); + out.open(); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/ppodlist.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ppodlist.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,192 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "ptypes.h" + + +PTYPES_BEGIN + + +void _podlist::idxerror() +{ + fatal(CRIT_FIRST + 30, "List index out of bounds"); +} + + +_podlist::_podlist(int iitemsize) + : list(0), count(0), capacity(0), itemsize(iitemsize) +{ + if (itemsize <= 0 || itemsize > 255) + fatal(CRIT_FIRST + 37, "Invalid item size for podlist"); +} + + +_podlist::~_podlist() +{ + set_count(0); +} + + +void _podlist::set_capacity(int newcap) +{ + if (newcap != capacity) + { + if (newcap < count) + fatal(CRIT_FIRST + 36, "List capacity can't be smaller than count"); + list = memrealloc(list, newcap * itemsize); + capacity = newcap; + } +} + + +void _podlist::grow() +{ + if (capacity > count) + return; + set_capacity(capacity == 0 ? 4 : ((capacity + 1) / 2) * 3); +} + + +void _podlist::set_count(int newcount, bool zero) +{ + if (newcount > count) + { + if (newcount > capacity) + set_capacity(newcount); + if (zero) + memset(doget(count), 0, (newcount - count) * itemsize); + count = newcount; + } + else if (newcount < count) + { + if (newcount < 0) + // wrong newcount: we don't want to generate an error here. + // instead, we'll set count to 0 and wait until some other + // operation raises an error + newcount = 0; + count = newcount; + if (count == 0) + set_capacity(0); + } +} + + +// doXXX() methods do not perform bounds checking; used internally +// where index is guaranteed to be valid + +void* _podlist::doins(int index) +{ + grow(); + pchar s = pchar(doget(index)); + if (index < count) + memmove(s + itemsize, s, (count - index) * itemsize); + count++; + return s; +} + + +void _podlist::doins(int index, const _podlist& t) +{ + if (&t == this) + return; + if (index == count) + add(t); + else + { + if (itemsize != t.itemsize) + fatal(CRIT_FIRST + 35, "Incompatible list"); + if (t.count == 0) + return; + int ocnt = count; + set_count(ocnt + t.count); + pchar s = pchar(doget(index)); + memmove(s + t.count * itemsize, s, (ocnt - index) * itemsize); + memcpy(s, t.list, t.count * itemsize); + } +} + + +void* _podlist::add() +{ + grow(); + return doget(count++); +} + + +void _podlist::add(const _podlist& t) +{ + if (count == 0) + operator =(t); + else + { + if (itemsize != t.itemsize) + fatal(CRIT_FIRST + 35, "Incompatible list"); + int ocnt = count; + int tcnt = t.count; + set_count(ocnt + tcnt); + memcpy(doget(ocnt), t.list, tcnt * itemsize); + } +} + + +_podlist& _podlist::operator =(const _podlist& t) +{ + if (&t != this) + { + if (itemsize != t.itemsize) + fatal(CRIT_FIRST + 35, "Incompatible list"); + set_count(t.count); + pack(); + memcpy(list, t.list, count * itemsize); + } + return *this; +} + + +void _podlist::dodel(int index) +{ + count--; + if (index < count) + { + pchar s = pchar(doget(index)); + memmove(s, s + itemsize, (count - index) * itemsize); + } + else if (count == 0) + set_capacity(0); +} + + +void _podlist::dodel(int index, int delcount) +{ + if (delcount <= 0) + return; + if (index + delcount > count) + delcount = count - index; + count -= delcount; + if (index < count) + { + pchar s = pchar(doget(index)); + memmove(s, s + delcount * itemsize, (count - index) * itemsize); + } + else if (count == 0) + set_capacity(0); +} + + +void _podlist::dopop() +{ + if (--count == 0) + set_capacity(0); +} + + +PTYPES_END + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pputf.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pputf.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,287 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include +#include +#include +#include + +#include "ptypes.h" +#include "pstreams.h" +#include "pinet.h" // for ipaddress type +#include "ptime.h" // for dttotm() + +#ifndef PTYPES_ST +#include "pasync.h" // for mutex locking in logfile::vputf() +#endif + + +PTYPES_BEGIN + + +// %t and %T formats +char* shorttimefmt = "%d-%b-%Y %X"; +char* longtimefmt = "%a %b %d %X %Y"; + + +static cset fmtopts = " #+~-0-9."; + + +enum fmt_type_t +{ + FMT_NONE, + FMT_CHAR, + FMT_SHORT, + FMT_INT, + FMT_LONG, + FMT_LARGE, + FMT_STR, + FMT_PTR, + FMT_DOUBLE, + FMT_LONG_DOUBLE, + FMT_IPADDR, + FMT_TIME, + FMT_LONGTIME +}; + + +void outstm::vputf(const char* fmt, va_list va) +{ + const char* p = fmt; + while (*p != 0) + { + // write out raw data between format specifiers + const char* e = strchr(p, '%'); + if (e == 0) + e = p + strlen(p); + if (e > p) + write(p, e - p); + + if (*e != '%') + break; + + e++; + if (*e == '%') + { + // write out a single '%' + put('%'); + p = e + 1; + continue; + } + + // build a temporary buffer for the conversion specification + char fbuf[128]; + fbuf[0] = '%'; + char* f = fbuf + 1; + bool modif = false; + + // formatting flags and width specifiers + while (*e & fmtopts && uint(f - fbuf) < sizeof(fbuf) - 5) + { + *f++ = *e++; + modif = true; + } + + // prefixes + fmt_type_t fmt_type = FMT_NONE; + switch(*e) + { + case 'h': + fmt_type = FMT_SHORT; + *f++ = *e++; + break; + case 'L': + fmt_type = FMT_LONG_DOUBLE; + *f++ = *e++; + break; + case 'l': + e++; + if (*e == 'l') + { +#if defined(_MSC_VER) || defined(__BORLANDC__) + *f++ = 'I'; + *f++ = '6'; + *f++ = '4'; +#else + *f++ = 'l'; + *f++ = 'l'; +#endif + e++; + fmt_type = FMT_LARGE; + } + else + { + *f++ = 'l'; + fmt_type = FMT_LONG; + } + break; + } + + // format specifier + switch(*e) + { + case 'c': + fmt_type = FMT_CHAR; + *f++ = *e++; + break; + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + if (fmt_type < FMT_SHORT || fmt_type > FMT_LARGE) + fmt_type = FMT_INT; + *f++ = *e++; + break; + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + if (fmt_type != FMT_LONG_DOUBLE) + fmt_type = FMT_DOUBLE; + *f++ = *e++; + break; + case 's': + fmt_type = FMT_STR; + *f++ = *e++; + break; + case 'p': + fmt_type = FMT_PTR; + *f++ = *e++; + break; + case 'a': + fmt_type = FMT_IPADDR; + *f++ = *e++; + break; + case 't': + fmt_type = FMT_TIME; + *f++ = *e++; + break; + case 'T': + fmt_type = FMT_LONGTIME; + *f++ = *e++; + break; + } + + if (fmt_type == FMT_NONE) + break; + + *f = 0; + + // some formatters are processed here 'manually', + // while others are passed to snprintf + char buf[4096]; + int s = 0; + switch(fmt_type) + { + case FMT_NONE: + break; // to avoid compiler warning + case FMT_CHAR: + if (modif) + s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,int)); + else + put(char(va_arg(va,int))); + break; + case FMT_SHORT: + s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,int)); + break; + case FMT_INT: + s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,int)); + break; + case FMT_LONG: + s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,long)); + break; + case FMT_LARGE: + s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,large)); + break; + case FMT_STR: + if (modif) + s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,char*)); + else + put(va_arg(va,const char*)); + break; + case FMT_PTR: + s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,void*)); + break; + case FMT_DOUBLE: + s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,double)); + break; + case FMT_LONG_DOUBLE: + s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,long double)); + break; + + case FMT_IPADDR: + { + ipaddress ip = va_arg(va,long); + s = snprintf(buf, sizeof(buf), "%d.%d.%d.%d", + uint(ip[0]), uint(ip[1]), uint(ip[2]), uint(ip[3])); + } + break; + + case FMT_TIME: + case FMT_LONGTIME: + { + char* fmt = fmt_type == FMT_TIME ? shorttimefmt : longtimefmt; + struct tm t; + datetime dt = va_arg(va,large); + if (dt < 0) + dt = 0; + s = strftime(buf, sizeof(buf), fmt, dttotm(dt, t)); + } + break; + } + if (s > 0) + write(buf, s); + + p = e; + } +} + + +void outstm::putf(const char* fmt, ...) +{ + va_list va; + va_start(va, fmt); + vputf(fmt, va); + va_end(va); +} + + +void fdxstm::putf(const char* fmt, ...) +{ + va_list va; + va_start(va, fmt); + out.vputf(fmt, va); + va_end(va); +} + + +void logfile::vputf(const char* fmt, va_list va) +{ +#ifndef PTYPES_ST + scopelock sl(lock); +#endif + outfile::vputf(fmt, va); +} + + +void logfile::putf(const char* fmt, ...) +{ + va_list va; + va_start(va, fmt); + vputf(fmt, va); + va_end(va); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/prwlock.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/prwlock.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,193 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +#endif + +#include "pasync.h" + + +PTYPES_BEGIN + + +static void rwlock_fail() +{ + fatal(CRIT_FIRST + 41, "rwlock failed"); +} + + +inline void rwlock_syscheck(int r) +{ + if (r != 0) + rwlock_fail(); +} + + +#ifdef __PTYPES_RWLOCK__ + + +# ifdef WIN32 + +// +// this implementation of the read/write lock is derived +// from Apache Portable Runtime (APR) source, which +// in turn was originally based on an erroneous (or just +// incomplete?) example in one of the MSDN technical articles. +// + +rwlock::rwlock() + : mutex(), readcnt(-1), writecnt(0) +{ + reading = CreateEvent(0, true, false, 0); + finished = CreateEvent(0, false, true, 0); + if (reading == 0 || finished == 0) + rwlock_fail(); +} + + +rwlock::~rwlock() +{ + CloseHandle(reading); + CloseHandle(finished); +} + + +void rwlock::rdlock() +{ + if (pincrement(&readcnt) == 0) + { + WaitForSingleObject(finished, INFINITE); + SetEvent(reading); + } + WaitForSingleObject(reading, INFINITE); +} + + +void rwlock::wrlock() +{ + mutex::enter(); + WaitForSingleObject(finished, INFINITE); + writecnt++; +} + + +void rwlock::unlock() +{ + if (writecnt != 0) + { + writecnt--; + SetEvent(finished); + mutex::leave(); + } + else if (pdecrement(&readcnt) < 0) + { + ResetEvent(reading); + SetEvent(finished); + } +} + + +# else // !defined(WIN32) + +// +// for other platforms that lack POSIX rwlock we implement +// the rwlock object using POSIX condvar. the code below +// is based on Sean Burke's algorithm posted in +// comp.programming.threads. +// + + +rwlock::rwlock() + : locks(0), writers(0), readers(0) +{ + rwlock_syscheck(pthread_mutex_init(&mtx, 0)); + rwlock_syscheck(pthread_cond_init(&readcond, 0)); + rwlock_syscheck(pthread_cond_init(&writecond, 0)); +} + + +rwlock::~rwlock() +{ + pthread_cond_destroy(&writecond); + pthread_cond_destroy(&readcond); + pthread_mutex_destroy(&mtx); +} + + +void rwlock::rdlock() +{ + pthread_mutex_lock(&mtx); + readers++; + while (locks < 0) + pthread_cond_wait(&readcond, &mtx); + readers--; + locks++; + pthread_mutex_unlock(&mtx); +} + + +void rwlock::wrlock() +{ + pthread_mutex_lock(&mtx); + writers++; + while (locks != 0) + pthread_cond_wait(&writecond, &mtx); + locks = -1; + writers--; + pthread_mutex_unlock(&mtx); +} + + +void rwlock::unlock() +{ + pthread_mutex_lock(&mtx); + if (locks > 0) + { + locks--; + if (locks == 0) + pthread_cond_signal(&writecond); + } + else + { + locks = 0; + if (readers != 0) + pthread_cond_broadcast(&readcond); + else + pthread_cond_signal(&writecond); + } + pthread_mutex_unlock(&mtx); +} + + +# endif // !defined(WIN32) + + +#else // !defined(__PTYPES_RWLOCK__) + +// +// for other systems we declare a fully-inlined rwlock +// object in pasync.h +// + +rwlock::rwlock() +{ + rwlock_syscheck(pthread_rwlock_init(&rw, 0)); +} + + +#endif + + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/psemaphore.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/psemaphore.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,76 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include + +#ifdef WIN32 +# include +#else +# include +#endif + +#include "pasync.h" + + +PTYPES_BEGIN + + +#ifndef __SEM_TO_TIMEDSEM__ + + +static void sem_fail() +{ + fatal(CRIT_FIRST + 41, "Semaphore failed"); +} + + +semaphore::semaphore(int initvalue) +{ + if (sem_init(&handle, 0, initvalue) != 0) + sem_fail(); +} + + +semaphore::~semaphore() +{ + sem_destroy(&handle); +} + + +void semaphore::wait() +{ + int err; + do { + err = sem_wait(&handle); + } while (err == -1 && errno == EINTR); + if (err != 0) + sem_fail(); +} + + +void semaphore::post() +{ + if (sem_post(&handle) != 0) + sem_fail(); +} + + +#else + + +int _psemaphore_dummy_symbol; // avoid ranlib's warning message + + +#endif + + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pstdio.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pstdio.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,155 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "pport.h" +#include "pstreams.h" + +#ifdef WIN32 +# include +#else +# include +#endif + + +PTYPES_BEGIN + +infile pin; +logfile pout; +logfile perr; +outnull pnull; + + +static class _stdio_init +{ +public: + _stdio_init(); +} _stdio_init_inst; + + +#ifdef WIN32 + +static HANDLE DuplicateSysHandle(DWORD stdh) +{ + HANDLE hold = GetStdHandle(stdh); + HANDLE hnew = 0; + DuplicateHandle(GetCurrentProcess(), hold, GetCurrentProcess(), + &hnew, 0, true, DUPLICATE_SAME_ACCESS); + return hnew; +} + +#endif + + +_stdio_init::_stdio_init() +{ +#ifdef WIN32 + pin.set_syshandle(int(DuplicateSysHandle(STD_INPUT_HANDLE))); + pout.set_syshandle(int(DuplicateSysHandle(STD_OUTPUT_HANDLE))); + perr.set_syshandle(int(DuplicateSysHandle(STD_ERROR_HANDLE))); +#else + pin.set_syshandle(::dup(STDIN_FILENO)); + pout.set_syshandle(::dup(STDOUT_FILENO)); + perr.set_syshandle(::dup(STDERR_FILENO)); +#endif + + pin.set_bufsize(4096); + pin.open(); + pout.open(); + perr.open(); + + pnull.open(); + + // prevent others from freeing these objects, if assigned to a variant. + // will need to handle reference counting for static objects better. any ideas? + addref(&pin); + addref(&pout); + addref(&perr); + addref(&pnull); + + // this is to show objalloc = 0 at program exit + objalloc -= 4; +} + + +// +// null output stream +// + + +outnull::outnull() + : outstm(0) +{ +} + + +outnull::~outnull() +{ + close(); +} + + +int outnull::dorawwrite(const char*, int) +{ + return 0; +} + + +void outnull::doopen() +{ +} + + +void outnull::doclose() +{ +} + + +string outnull::get_streamname() +{ + return ""; +} + + +// +// logfile - file output with thread-safe putf() +// + +logfile::logfile(): outfile() +{ + set_bufsize(0); +} + + +logfile::logfile(const char* ifn, bool iappend): outfile(ifn, iappend) +{ + set_bufsize(0); +} + + +logfile::logfile(const string& ifn, bool iappend): outfile(ifn, iappend) +{ + set_bufsize(0); +} + + +logfile::~logfile() +{ +} + + +int logfile::classid() +{ + return CLASS3_LOGFILE; +} + + +PTYPES_END + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pstrcase.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pstrcase.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,73 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "ptypes.h" + + +PTYPES_BEGIN + + +string ptdecl lowercase(const char* p) +{ + // we rely on the function locase() which converts one single + // character to lower case. all locale specific things can be + // settled down in the future releases. + string r; + if (p != nil) + { + char* d = setlength(r, strlen(p)); + while (*p != 0) + *d++ = locase(*p++); + } + return r; +} + + +string ptdecl lowercase(const string& s) +{ + // this function does practically nothing if the string s + // contains no uppercase characters. once an uppercase character + // is encountered, the string is copied to another buffer and the + // rest is done as usual. + + string r = s; + + // a trick to get a non-const pointer without making + // the string unique + char* p = pchar(pconst(r)); + bool u = false; + int i = 0; + + while (*p != 0) + { + char c = locase(*p); + // if the character went lowercase... + if (c != *p) + { + // if the resulting string r is not unique yet... + if (!u) + { + // ... make it unique and adjust the pointer p accordingly + // this is done only once. + p = unique(r) + i; + u = true; + } + *p = c; + } + p++; + i++; + } + + return r; +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pstrconv.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pstrconv.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,147 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include + +#include "ptypes.h" + + +PTYPES_BEGIN + + +static char* _itobase(large value, char* buf, int base, int& len, bool _signed) +{ + // internal conversion routine: converts the value to a string + // at the end of the buffer and returns a pointer to the first + // character. this is to get rid of copying the string to the + // beginning of the buffer, since finally the string is supposed + // to be copied to a dynamic string in itostring(). the buffer + // must be at least 65 bytes long. + + static char digits[65] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + char* pdigits; + if (base > 36) + pdigits = digits; // start from '.' + else + pdigits = digits + 2; // start from '0' + + int i = 64; + buf[i] = 0; + + bool neg = false; + ularge v = value; + if (_signed && base == 10 && value < 0) + { + v = -value; + // since we can't handle the lowest signed 64-bit value, we just + // return a built-in string. + if (large(v) < 0) // the LLONG_MIN negated results in the same value + { + len = 20; + return "-9223372036854775808"; + } + neg = true; + } + + do + { + buf[--i] = pdigits[uint(v % base)]; + v /= base; + } while (v > 0); + + if (neg) + buf[--i] = '-'; + + len = 64 - i; + return buf + i; +} + + +static void _itobase2(string& result, large value, int base, int width, char padchar, bool _signed) +{ + if (base < 2 || base > 64) + { + clear(result); + return; + } + + char buf[65]; // the longest possible string is when base=2 + int reslen; + char* p = _itobase(value, buf, base, reslen, _signed); + + if (width > reslen) + { + if (padchar == 0) + { + // default pad char + if (base == 10) + padchar = ' '; + else if (base > 36) + padchar = '.'; + else + padchar = '0'; + } + + setlength(result, width); + bool neg = *p == '-'; + width -= reslen; + memset(pchar(pconst(result)) + neg, padchar, width); + memcpy(pchar(pconst(result)) + width + neg, p + neg, reslen - neg); + if (neg) + *pchar(pconst(result)) = '-'; + } + else + assign(result, p, reslen); +} + + +string ptdecl itostring(large value, int base, int width, char padchar) +{ + string result; + _itobase2(result, value, base, width, padchar, true); + return result; +} + + +string ptdecl itostring(ularge value, int base, int width, char padchar) +{ + string result; + _itobase2(result, value, base, width, padchar, false); + return result; +} + + +string ptdecl itostring(int value, int base, int width, char padchar) +{ + string result; + _itobase2(result, large(value), base, width, padchar, true); + return result; +} + + +string ptdecl itostring(uint value, int base, int width, char padchar) +{ + string result; + _itobase2(result, ularge(value), base, width, padchar, false); + return result; +} + + +string ptdecl itostring(large v) { return itostring(v, 10, 0, ' '); } +string ptdecl itostring(ularge v) { return itostring(v, 10, 0, ' '); } +string ptdecl itostring(int v) { return itostring(large(v), 10, 0, ' '); } +string ptdecl itostring(uint v) { return itostring(ularge(v), 10, 0, ' '); } + + +PTYPES_END + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pstring.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pstring.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,289 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include +#include +#include + +#include "ptypes.h" +#include "ptime.h" // nowstring() is defined in this module + + +PTYPES_BEGIN + + +const int strrecsize = sizeof(_strrec); + + +static void stringoverflow() +{ + fatal(CRIT_FIRST + 21, "String overflow"); +} + + +void string::idxerror() +{ + fatal(CRIT_FIRST + 20, "String index overflow"); +} + + +int stralloc; + +char emptystrbuf[strrecsize + 4]; +char* emptystr = emptystrbuf + strrecsize; + + +string nullstring; + + +inline int quantize(int numchars) +{ + return memquantize(numchars + 1 + strrecsize); +} + + +void string::_alloc(int numchars) +{ + if (numchars <= 0) + stringoverflow(); + size_t a = quantize(numchars); +#ifdef DEBUG + stralloc += a; +#endif + data = (char*)(memalloc(a)) + strrecsize; + STR_LENGTH(data) = numchars; + STR_REFCOUNT(data) = 1; + data[numchars] = 0; +} + + +void string::_realloc(int numchars) +{ + if (numchars <= 0 || STR_LENGTH(data) <= 0) + stringoverflow(); + int a = quantize(numchars); + int b = quantize(STR_LENGTH(data)); + if (a != b) + { +#ifdef DEBUG + stralloc += a - b; +#endif + data = (char*)(memrealloc(data - strrecsize, a)) + strrecsize; + } + STR_LENGTH(data) = numchars; + data[numchars] = 0; +} + + +inline void _freestrbuf(char* data) +{ +#ifdef DEBUG + stralloc -= quantize(STR_LENGTH(data)); +#endif + memfree((char*)(STR_BASE(data))); +} + + +void string::_free() +{ + _freestrbuf(data); + data = emptystr; +} + + +void string::initialize(const char* sc, int initlen) +{ + if (initlen <= 0 || sc == nil) + data = emptystr; + else + { + _alloc(initlen); + memmove(data, sc, initlen); + } +} + + +void string::initialize(const char* sc) +{ + initialize(sc, hstrlen(sc)); +} + + +void string::initialize(char c) +{ + _alloc(1); + data[0] = c; +} + + +void string::initialize(const string& s) +{ + data = s.data; +#ifdef PTYPES_ST + STR_REFCOUNT(data)++; +#else + pincrement(&STR_REFCOUNT(data)); +#endif +} + + +void string::finalize() +{ + if (STR_LENGTH(data) != 0) + { + +#ifdef PTYPES_ST + if (--STR_REFCOUNT(data) == 0) +#else + if (pdecrement(&STR_REFCOUNT(data)) == 0) +#endif + _freestrbuf(data); + + data = emptystr; + } +} + + +char* ptdecl unique(string& s) +{ + if (STR_LENGTH(s.data) > 0 && STR_REFCOUNT(s.data) > 1) + { + char* odata = s.data; + s._alloc(STR_LENGTH(s.data)); + memcpy(s.data, odata, STR_LENGTH(s.data)); +#ifdef PTYPES_ST + STR_REFCOUNT(odata)--; +#else + if (pdecrement(&STR_REFCOUNT(odata)) == 0) + _freestrbuf(odata); +#endif + } + return s.data; +} + + +char* ptdecl setlength(string& s, int newlen) +{ + if (newlen < 0) + return nil; + + int curlen = STR_LENGTH(s.data); + + // if becoming empty + if (newlen == 0) + s.finalize(); + + // if otherwise s was empty before + else if (curlen == 0) + s._alloc(newlen); + + // if length is not changing, return a unique string + else if (newlen == curlen) + unique(s); + + // non-unique reallocation + else if (STR_REFCOUNT(s.data) > 1) + { + char* odata = s.data; + s._alloc(newlen); + memcpy(s.data, odata, imin(curlen, newlen)); +#ifdef PTYPES_ST + STR_REFCOUNT(odata)--; +#else + if (pdecrement(&STR_REFCOUNT(odata)) == 0) + _freestrbuf(odata); +#endif + } + + // unique reallocation + else + s._realloc(newlen); + + return s.data; +} + + +void string::assign(const char* sc, int initlen) +{ + if (STR_LENGTH(data) > 0 && initlen > 0 && STR_REFCOUNT(data) == 1) + { + // reuse data buffer if unique + _realloc(initlen); + memmove(data, sc, initlen); + } + else + { + finalize(); + if (initlen == 1) + initialize(sc[0]); + else if (initlen > 1) + initialize(sc, initlen); + } +} + + +void string::assign(const char* sc) +{ + assign(sc, hstrlen(sc)); +} + + +void string::assign(char c) +{ + assign(&c, 1); +} + + +void string::assign(const string& s) +{ + if (data != s.data) + { + finalize(); + initialize(s); + } +} + + +string ptdecl dup(const string& s) +{ + // dup() only reads the data pointer so it is thread-safe + return string(s.data); +} + + +string ptdecl nowstring(const char* fmt, bool utc) +{ + char buf[128]; + time_t longtime; + time(&longtime); + +#if defined(PTYPES_ST) || defined(WIN32) + tm* t; + if (utc) + t = gmtime(&longtime); + else + t = localtime(&longtime); + int r = strftime(buf, sizeof(buf), fmt, t); +#else + tm t; + if (utc) + gmtime_r(&longtime, &t); + else + localtime_r(&longtime, &t); + int r = strftime(buf, sizeof(buf), fmt, &t); +#endif + + buf[r] = 0; + return string(buf); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pstrlist.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pstrlist.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,204 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "ptypes.h" + + +PTYPES_BEGIN + + +typedef _stritem* pstritem; + + +void _strlist::sortederror() +{ + fatal(CRIT_FIRST + 32, "Operation not allowed on sorted string lists"); +} + + +void _strlist::notsortederror() +{ + fatal(CRIT_FIRST + 33, "Search only allowed on sorted string lists"); +} + + +void _strlist::duperror() +{ + fatal(CRIT_FIRST + 34, "Duplicate items not allowed in this string list"); +} + + +_strlist::_strlist(int flags) + : tobjlist<_stritem>(true) +{ + if ((flags & SL_SORTED) != 0) + config.sorted = 1; + if ((flags & SL_DUPLICATES) != 0) + config.duplicates = 1; + if ((flags & SL_CASESENS) != 0) + config.casesens = 1; + if ((flags & SL_OWNOBJECTS) != 0) + config.ownslobjects = 1; +} + + +_strlist::~_strlist() +{ +} + + +void _strlist::dofree(void* item) +{ + if (config.ownslobjects) + dofreeobj(pstritem(item)->obj); + delete pstritem(item); +} + + +void _strlist::dofreeobj(void*) +{ + fatal(CRIT_FIRST + 38, "strlist::dofree() not defined"); +} + + +int _strlist::compare(const void* key, const void* item) const +{ + if (config.casesens) + return strcmp(pconst(key), pstritem(item)->key); + else + return strcasecmp(pconst(key), pstritem(item)->key); +} + + +void _strlist::doins(int index, const string& key, void* obj) +{ + tobjlist<_stritem>::ins(index, new _stritem(key, obj)); +} + + +void _strlist::doput(int index, const string& key, void* obj) +{ + if (config.sorted) + sortederror(); + _stritem* p = doget(index); + if (config.ownslobjects) + dofreeobj(p->obj); + p->key = key; + p->obj = obj; +} + + +void _strlist::doput(int index, void* obj) +{ + _stritem* p = doget(index); + if (config.ownslobjects) + dofreeobj(p->obj); + p->obj = obj; +} + + +int _strlist::put(const string& key, void* obj) +{ + if (!config.sorted) + notsortederror(); + if (config.duplicates) + duperror(); + int index; + if (search(key, index)) + { + if (obj == nil) + dodel(index); + else + doput(index, obj); + } + else if (obj != nil) + doins(index, key, obj); + return index; +} + + +int _strlist::add(const string& key, void* obj) +{ + int index; + if (config.sorted) + { + if (search(key, index) && !config.duplicates) + duperror(); + } + else + index = count; + doins(index, key, obj); + return index; +} + + +void* _strlist::operator [](const char* key) const +{ + if (!config.sorted) + notsortederror(); + int index; + if (search(key, index)) + return dogetobj(index); + else + return nil; +} + + +int _strlist::indexof(const char* key) const +{ + if (config.sorted) + { + int index; + if (search(key, index)) + return index; + } + else + { + for (int i = 0; i < count; i++) + if (compare(key, doget(i)) == 0) + return i; + } + return -1; +} + + +int _strlist::indexof(void* obj) const +{ + for (int i = 0; i < count; i++) + if (pstritem(doget(i))->obj == obj) + return i; + return -1; +} + + +// +// strmap +// + +#ifdef PTYPES19_COMPAT + +strlist::strlist(int flags): tstrlist(flags) {} + +strlist::~strlist() {} + +strmap::strmap(int flags) + : tstrlist((flags | SL_SORTED) & ~SL_DUPLICATES) +{ +} + +strmap::~strmap() +{ +} + +#endif + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pstrmanip.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pstrmanip.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,281 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include +#include +#include // for INT_MAX + +#include "ptypes.h" + + +PTYPES_BEGIN + + +void string::initialize(const char* s1, int len1, const char* s2, int len2) +{ + if (len1 <= 0) + initialize(s2, len2); + else if (len2 <= 0) + initialize(s1, len1); + else + { + _alloc(len1 + len2); + memcpy(data, s1, len1); + memcpy(data + len1, s2, len2); + } +} + + +void ptdecl concat(string& s, const char* sc, int catlen) +{ + if (length(s) == 0) + s.assign(sc, catlen); + else if (catlen > 0) + { + int oldlen = length(s); + + // we must check this before calling setlength(), since + // the buffer pointer may be changed during reallocation + if (s.data == sc) + { + setlength(s, oldlen + catlen); + memmove(s.data + oldlen, s.data, catlen); + } + else + { + setlength(s, oldlen + catlen); + memmove(s.data + oldlen, sc, catlen); + } + } +} + + +void ptdecl concat(string& s, const char* sc) +{ + concat(s, sc, hstrlen(sc)); +} + + +void ptdecl concat(string& s, char c) +{ + if (length(s) == 0) + s.assign(c); + else + { + setlength(s, length(s) + 1); + s.data[length(s) - 1] = c; + } +} + + +void ptdecl concat(string& s, const string& s1) +{ + if (length(s) == 0) + s = s1; + else if (length(s1) > 0) + concat(s, s1.data, length(s1)); +} + + +bool ptdecl contains(const char* s1, int s1len, const string& s, int at) +{ + return (s1len >= 0) && (at >= 0) && (at + s1len <= length(s)) + && (s1len == 0 || memcmp(s.data + at, s1, s1len) == 0); +} + + +bool ptdecl contains(const char* s1, const string& s, int at) +{ + return contains(s1, hstrlen(s1), s, at); +} + + +bool ptdecl contains(char s1, const string& s, int at) +{ + return (at >= 0) && (at < length(s)) && (s.data[at] == s1); +} + + +bool ptdecl contains(const string& s1, const string& s, int at) +{ + return contains(s1.data, length(s1), s, at); +} + + +string string::operator+ (const char* sc) const +{ + if (length(*this) == 0) + return string(sc); + else + return string(data, length(*this), sc, hstrlen(sc)); +} + + +string string::operator+ (char c) const +{ + if (length(*this) == 0) + return string(c); + else + return string(data, length(*this), &c, 1); +} + + +string string::operator+ (const string& s) const +{ + if (length(*this) == 0) + return s; + else if (length(s) == 0) + return *this; + else + return string(data, length(*this), s.data, length(s)); +} + + +string ptdecl operator+ (const char* sc, const string& s) +{ + if (length(s) == 0) + return string(sc); + else + return string(sc, hstrlen(sc), s.data, length(s)); +} + + +string ptdecl operator+ (char c, const string& s) +{ + if (length(s) == 0) + return string(c); + else + return string(&c, 1, s.data, length(s)); +} + + +bool string::operator== (const string& s) const +{ + return (length(*this) == length(s)) + && ((length(*this) == 0) || (memcmp(data, s.data, length(*this)) == 0)); +} + + +bool string::operator== (char c) const +{ + return (length(*this) == 1) && (data[0] == c); +} + + +string ptdecl copy(const string& s, int from, int cnt) +{ + string t; + if (length(s) > 0 && from >= 0 && from < length(s)) + { + int l = imin(cnt, length(s) - from); + if (from == 0 && l == length(s)) + t = s; + else if (l > 0) + { + t._alloc(l); + memmove(t.data, s.data + from, l); + t.data[l] = 0; + } + } + return t; +} + + +string ptdecl copy(const string& s, int from) +{ + return copy(s, from, INT_MAX); +} + + +void ptdecl ins(const char* s1, int s1len, string& s, int at) +{ + int curlen = length(s); + if (s1len > 0 && at >= 0 && at <= curlen) + { + if (curlen == 0) + s.assign(s1, s1len); + else + { + setlength(s, curlen + s1len); + int t = length(s) - at - s1len; + char* p = s.data + at; + if (t > 0) + memmove(p + s1len, p, t); + memmove(p, s1, s1len); + } + } +} + + +void ptdecl ins(const char* sc, string& s, int at) +{ + ins(sc, hstrlen(sc), s, at); +} + + +void ptdecl ins(char c, string& s, int at) +{ + ins(&c, 1, s, at); +} + + +void ptdecl ins(const string& s1, string& s, int at) +{ + ins(s1.data, length(s1), s, at); +} + + +void ptdecl del(string& s, int from, int cnt) +{ + int l = length(s); + int d = l - from; + if (from >= 0 && d > 0 && cnt > 0) + { + if (cnt < d) + { + unique(s); + memmove(s.data + from, s.data + from + cnt, d - cnt); + } + else + cnt = d; + setlength(s, l - cnt); + } +} + + +void ptdecl del(string& s, int from) +{ + setlength(s, from); +} + + +int ptdecl pos(const char* sc, const string& s) +{ + const char* t = (char*)strstr(s.data, sc); + return (t == NULL ? (-1) : (t - s.data)); +} + + +int ptdecl pos(char c, const string& s) +{ + const char* t = (char*)strchr(s.data, c); + return (t == NULL ? (-1) : (t - s.data)); +} + + +int ptdecl rpos(char c, const string& s) +{ + const char* t = (char*)strrchr(s.data, c); + return (t == NULL ? (-1) : (t - s.data)); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pstrtoi.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pstrtoi.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,136 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include + +#include "ptypes.h" + + +PTYPES_BEGIN + + +static void throw_conv(const char* p); +static void throw_overflow(const char* p); + + +large ptdecl stringtoi(const char* p) +{ + if (p == 0) + return -1; + if (*p == 0) + return -1; + + large r = 0; + do + { + char c = *p++; + if (c < '0' || c > '9') + return -1; // invalid character + large t = r * 10; + if (t < r) + return -1; // overflow + t += c - '0'; + if (t < r) + return -1; // overflow + r = t; + } while (*p != 0); + + return r; +} + + +econv::~econv() +{ +} + + +ularge ptdecl stringtoue(const char* str, int base) +{ + if (str == 0) + throw_conv(str); + if (*str == 0 || base < 2 || base > 64) + throw_conv(str); + + const char* p = str; + ularge result = 0; + + do + { + int c = *p++; + + if (c >= 'a') + { + // for the numeration bases that use '.', '/', digits and + // uppercase letters the letter case is insignificant. + if (base <= 38) + c -= 'a' - '9' - 1; + else // others use both upper and lower case letters + c -= ('a' - 'Z' - 1) + ('A' - '9' - 1); + } + else if (c > 'Z') + throw_conv(str); + else if (c >= 'A') + c -= 'A' - '9' - 1; + else if (c > '9') + throw_conv(str); + + c -= (base > 36) ? '.' : '0'; + if (c < 0 || c >= base) + throw_conv(str); + + ularge t = result * uint(base); + if (t / base != result) + throw_overflow(str); + result = t; + t = result + uint(c); + if (t < result) + throw_overflow(str); + result = t; + } while (*p != 0); + + return result; +} + + +large ptdecl stringtoie(const char* str) +{ + if (str == 0) + throw_conv(str); + bool neg = *str == '-'; + ularge result = stringtoue(str + int(neg), 10); + if (result > (ularge(LARGE_MAX) + uint(neg))) + throw_overflow(str); + if (neg) + return - large(result); + else + return large(result); +} + + +#ifdef _MSC_VER +// disable "unreachable code" warning for throw (known compiler bug) +# pragma warning (disable: 4702) +#endif + +static void throw_conv(const char* p) +{ + throw new econv("Invalid number: '" + string(p) + '\''); +} + + +static void throw_overflow(const char* p) +{ + throw new econv("Out of range: '" + string(p) + '\''); +} + + +PTYPES_END + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pstrutils.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pstrutils.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,57 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include + +#include "ptypes.h" + + +PTYPES_BEGIN + + +string ptdecl fill(int width, char pad) +{ + string res; + if (width > 0) { + setlength(res, width); + memset(pchar(pconst(res)), pad, length(res)); + } + return res; +} + + +string ptdecl pad(const string& s, int width, char c, bool left) +{ + int len = length(s); + if (len < width && width > 0) + { + string res; + setlength(res, width); + if (left) + { + if (len > 0) + memcpy(pchar(pconst(res)), pconst(s), len); + memset(pchar(pconst(res)) + len, c, width - len); + } + else + { + memset(pchar(pconst(res)), c, width - len); + if (len > 0) + memcpy(pchar(pconst(res)) + width - len, pconst(s), len); + } + return res; + } + else + return s; +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/ptextmap.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ptextmap.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,79 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "ptypes.h" + + +PTYPES_BEGIN + + +typedef _textitem* ptextitem; + + +textmap::textmap(bool casesens) + : tobjlist<_textitem>(true) +{ + config.sorted = true; + config.casesens = casesens; +} + + +textmap::~textmap() +{ +} + + +int textmap::compare(const void* key, const void* item) const +{ + if (config.casesens) + return strcmp(pconst(key), ptextitem(item)->key); + else + return strcasecmp(pconst(key), ptextitem(item)->key); +} + + +const string& textmap::get(const char* key) const +{ + int index; + if (search(key, index)) + return dogetvalue(index); + else + return nullstring; +} + + +int textmap::put(const string& key, const string& value) +{ + int index; + if (search(pconst(key), index)) + { + if (isempty(value)) + dodel(index); + else + doget(index)->value = value; + } + else if (!isempty(value)) + doins(index, new _textitem(key, value)); + return index; +} + + +int textmap::indexof(const char* key) const +{ + int index; + if (search(key, index)) + return index; + else + return -1; +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pthread.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pthread.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,154 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +#endif + +#include "pasync.h" + + +PTYPES_BEGIN + + +thread::thread(bool iautofree) + : +#ifdef WIN32 + id(0), +#endif + handle(0), autofree(iautofree), + running(0), signaled(0), finished(0), freed(0), + reserved(0), relaxsem(0) +{ +} + + +thread::~thread() +{ + if (pexchange(&freed, 1) != 0) + return; +#ifdef WIN32 + if (autofree) + // MSDN states this is not necessary, however, without closing + // the handle debuggers show an obvious handle leak here + CloseHandle(handle); +#else + // though we require non-autofree threads to always call waitfor(), + // the statement below is provided to cleanup thread resources even + // if waitfor() was not called. + if (!autofree && running) + pthread_detach(handle); +#endif +} + + +void thread::signal() +{ + if (pexchange(&signaled, 1) == 0) + relaxsem.post(); +} + + +void thread::waitfor() +{ + if (pexchange(&freed, 1) != 0) + return; + if (pthrequal(get_id())) + fatal(CRIT_FIRST + 47, "Can not waitfor() on myself"); + if (autofree) + fatal(CRIT_FIRST + 48, "Can not waitfor() on an autofree thread"); +#ifdef WIN32 + WaitForSingleObject(handle, INFINITE); + CloseHandle(handle); +#else + pthread_join(handle, nil); +// detaching after 'join' is not required (or even do harm on some systems) +// except for HPUX. we don't support HPUX yet. +// pthread_detach(handle); +#endif + handle = 0; +} + + +#ifdef WIN32 +unsigned _stdcall _threadproc(void* arg) +{ +#else +void* _threadproc(void* arg) +{ +#endif + thread* thr = (thread*)arg; +#ifndef WIN32 + if (thr->autofree) + // start() does not assign the handle for autofree threads + thr->handle = pthread_self(); +#endif + try + { + thr->execute(); + } + catch(exception*) + { + _threadepilog(thr); + throw; + } + _threadepilog(thr); + return 0; +} + + +void _threadepilog(thread* thr) +{ + try + { + thr->cleanup(); + } + catch(exception* e) + { + delete e; + } + pexchange(&thr->finished, 1); + if (thr->autofree) + delete thr; +} + + +void thread::start() +{ + if (pexchange(&running, 1) == 0) + { +#ifdef WIN32 + handle = (HANDLE)_beginthreadex(nil, 0, _threadproc, this, 0, &id); + if (handle == 0) + fatal(CRIT_FIRST + 40, "CreateThread() failed"); +#else + pthread_t temp_handle; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, + autofree ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE); + if (pthread_create(autofree ? &temp_handle : &handle, + &attr, _threadproc, this) != 0) + fatal(CRIT_FIRST + 40, "pthread_create() failed"); + pthread_attr_destroy(&attr); +#endif + } +} + + +void thread::cleanup() +{ +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/ptime.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ptime.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,325 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +// altzone fix for Sun/GCC 3.2. any better ideas? +#if defined(__sun__) && defined(__GNUC__) && defined(_XOPEN_SOURCE) +# undef _XOPEN_SOURCE +#endif + +#ifdef WIN32 +# include +#else +# include +#endif + +#include +#include + +#include "ptime.h" + + +PTYPES_BEGIN + + +datetime ptdecl mkdt(int days, int msecs) +{ + return large(days) * _msecsmax + msecs; +} + + +bool ptdecl isvalid(datetime d) +{ + return d >= 0 && d < _datetimemax; +} + + +bool ptdecl isleapyear(int year) +{ + return year > 0 && year % 4 == 0 + && (year % 100 != 0 || year % 400 == 0); +} + + +int ptdecl daysinmonth(int year, int month) +{ + if (month < 1 || month > 12) + return 0; + static const int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + int res = mdays[month - 1]; + if (month == 2) + if (isleapyear(year)) + res++; + return res; +} + + +int ptdecl daysinyear(int year, int month) +{ + if (month < 1 || month > 12) + return 0; + static const int ndays[12] = {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; + int res = ndays[month - 1]; + if (month > 1) + if (isleapyear(year)) + res++; + return res; +} + + +int ptdecl dayofweek(datetime d) +{ + return (days(d) + 1) % 7; +} + + +bool ptdecl isdatevalid(int year, int month, int day) +{ + return year >= 1 && year <= 9999 + && month >= 1 && month <= 12 + && day >= 1 && day <= daysinmonth(year, month); +} + + +datetime ptdecl encodedate(int year, int month, int day) +{ + if (!isdatevalid(year, month, day)) + return invdatetime; + int y = year - 1; + return mkdt(day // days in this month + + daysinyear(year, month - 1) // plus days since the beginning of the year + + y * 365 // plus "pure" days + + y / 4 - y / 100 + y / 400 // plus leap year correction + - 1, 0); // ... minus one (guess why :) +} + + +bool ptdecl decodedate(datetime date, int& year, int& month, int& day) +{ + int d = days(date); + if (d < 0 || d >= _daysmax) // allowed date range is 01/01/0001 - 12/31/9999 + { + year = 0; + month = 0; + day = 0; + return false; + } + + const int d1 = 365; // number of days in 1 year + const int d4 = d1 * 4 + 1; // ... in 4 year period + const int d100 = d4 * 25 - 1; // ... in 100 year period + const int d400 = d100 * 4 + 1; // ... in 400 year period + + year = (d / d400) * 400 + 1; + d %= d400; + + int t = d / d100; + d %= d100; + if (t == 4) + { + t--; + d += d100; + } + year += t * 100; + + year += (d / d4) * 4; + d %= d4; + + t = d / d1; + d %= d1; + if (t == 4) + { + t--; + d += d1; + } + year += t; + + month = d / 29; // approximate month no. (to avoid loops) + if (d < daysinyear(year, month)) // month no. correction + month--; + + day = d - daysinyear(year, month) + 1; + month++; + return true; +} + + +bool ptdecl istimevalid(int hour, int min, int sec, int msec) +{ + return hour >= 0 && hour < 24 + && min >= 0 && min < 60 + && sec >= 0 && sec < 60 + && msec >= 0 && msec < 1000; +} + + +datetime ptdecl encodetime(int hour, int min, int sec, int msec) +{ + large res = large(hour) * 3600000 + large(min) * 60000 + large(sec) * 1000 + msec; + if (!isvalid(res)) + res = invdatetime; + return res; +} + + +bool ptdecl decodetime(datetime t, int& hour, int& min, int& sec, int& msec) +{ + if (!isvalid(t)) + { + hour = 0; + min = 0; + sec = 0; + msec = 0; + return false; + } + int m = msecs(t); + hour = m / 3600000; + m %= 3600000; + min = m / 60000; + m %= 60000; + sec = m / 1000; + msec = m % 1000; + return true; +} + + +bool ptdecl decodetime(datetime t, int& hour, int& min, int& sec) +{ + int msec; + return decodetime(t, hour, min, sec, msec); +} + + +tm* ptdecl dttotm(datetime dt, tm& t) +{ + memset(&t, 0, sizeof(tm)); + if (!decodedate(dt, t.tm_year, t.tm_mon, t.tm_mday) + || !decodetime(dt, t.tm_hour, t.tm_min, t.tm_sec)) + return nil; + t.tm_mon--; + t.tm_yday = daysinyear(t.tm_year, t.tm_mon) + t.tm_mday - 1; + t.tm_wday = dayofweek(dt); + t.tm_year -= 1900; + return &t; +} + + +string ptdecl dttostring(datetime dt, const char* fmt) +{ + char buf[128]; + tm t; + int r = strftime(buf, sizeof(buf), fmt, dttotm(dt, t)); + buf[r] = 0; + return string(buf); +} + + +datetime ptdecl now(bool utc) +{ +#ifdef WIN32 + SYSTEMTIME t; + if (utc) + GetSystemTime(&t); + else + GetLocalTime(&t); + return encodedate(t.wYear, t.wMonth, t.wDay) + + encodetime(t.wHour, t.wMinute, t.wSecond, t.wMilliseconds); + +#else // Unix + // we can't use localtime() and gmtime() here as they don't return + // milliseconds which are needed for our datetime format. instead, + // we call gettimeofday() which have microsecond precision, and then + // adjust the time according to timzone info returned by localtime() + // on BSD and Linux, and global variables altzone/timezone on SunOS. + + // NOTE: at the moment of passing the DST adjustment (twice a year) + // the local time value returned by now() may be incorrect. + // the application should call tzupdate() from time to time if it + // is supposed to be running infinitely, e.g. if it's a daemon. + + // always rely on UTC time inside your application whenever possible. + timeval tv; + gettimeofday(&tv, nil); + int edays = tv.tv_sec / 86400 // days since Unix "Epoch", i.e. 01/01/1970 + + 719162; // plus days between 01/01/0001 and Unix Epoch + int esecs = tv.tv_sec % 86400; // the remainder, i.e. seconds since midnight + datetime res = mkdt(edays, esecs * 1000 + tv.tv_usec / 1000); + + if (!utc) + res += tzoffset() * 60 * 1000; + return res; +#endif +} + + +void ptdecl tzupdate() +{ + tzset(); +} + + +int ptdecl tzoffset() +{ +#if defined(WIN32) + TIME_ZONE_INFORMATION tz; + DWORD res = GetTimeZoneInformation(&tz); + if ((res == TIME_ZONE_ID_DAYLIGHT) && (tz.DaylightDate.wMonth != 0)) + return - (tz.Bias + tz.DaylightBias); + else + return - tz.Bias; + +#else // UNIX + time_t t0 = time(0); + +#if defined(__sun__) +#ifdef PTYPES_ST + // localtime_r() is not available without -D_REENTRANT + tm* t = localtime(&t0); + if(t->tm_isdst != 0 && daylight != 0) +#else + tm t; + localtime_r(&t0, &t); + if(t.tm_isdst != 0 && daylight != 0) +#endif + return - altzone / 60; + else + return - timezone / 60; + +#elif defined(__CYGWIN__) + time_t local_time = time(NULL); + tm gt; + gmtime_r(&local_time, >); + time_t gmt_time = mktime(>); + return (local_time - gmt_time) / 60; + +#elif defined(__hpux) + tm local; + localtime_r(&t0, &local); + local.tm_isdst = 0; + time_t t1 = mktime(&local); + return - (timezone - (t1 - t0)) / 60; + +#else // other UNIX + tm t; + localtime_r(&t0, &t); + return t.tm_gmtoff / 60; +#endif + +#endif +} + + +datetime ptdecl utodatetime(time_t u) +{ + return _unixepoch + large(u) * 1000; +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/ptimedsem.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ptimedsem.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,130 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +# include +# include +#endif + +#include "pasync.h" + + +PTYPES_BEGIN + + +static void tsem_fail() +{ + fatal(CRIT_FIRST + 41, "Timed semaphore failed"); +} + + +#ifdef WIN32 + + +timedsem::timedsem(int initvalue) +{ + handle = CreateSemaphore(nil, initvalue, 65535, nil); + if (handle == 0) + tsem_fail(); +} + + +timedsem::~timedsem() +{ + CloseHandle(handle); +} + + +bool timedsem::wait(int timeout) +{ + uint r = WaitForSingleObject(handle, timeout); + if (r == WAIT_FAILED) + tsem_fail(); + return r != WAIT_TIMEOUT; +} + + +void timedsem::post() +{ + if (ReleaseSemaphore(handle, 1, nil) == 0) + tsem_fail(); +} + + +#else + + +inline void tsem_syscheck(int r) +{ + if (r != 0) + tsem_fail(); +} + + +timedsem::timedsem(int initvalue) + : unknown(), count(initvalue) +{ + tsem_syscheck(pthread_mutex_init(&mtx, 0)); + tsem_syscheck(pthread_cond_init(&cond, 0)); +} + + +timedsem::~timedsem() +{ + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&mtx); +} + + +bool timedsem::wait(int timeout) +{ + pthread_mutex_lock(&mtx); + while (count <= 0) + { + if (timeout >= 0) + { + timespec abs_ts; + timeval cur_tv; + gettimeofday(&cur_tv, NULL); + abs_ts.tv_sec = cur_tv.tv_sec + timeout / 1000; + abs_ts.tv_nsec = cur_tv.tv_usec * 1000 + + (timeout % 1000) * 1000000; + int rc = pthread_cond_timedwait(&cond, &mtx, &abs_ts); + if (rc == ETIMEDOUT) { + pthread_mutex_unlock(&mtx); + return false; + } + } + else + pthread_cond_wait(&cond, &mtx); + } + count--; + pthread_mutex_unlock(&mtx); + return true; +} + + +void timedsem::post() +{ + pthread_mutex_lock(&mtx); + count++; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mtx); +} + + +#endif + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/ptrigger.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ptrigger.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,101 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#ifdef WIN32 +# include +#else +# include +# include +# include +#endif + +#include "pasync.h" + + +PTYPES_BEGIN + + +static void trig_fail() +{ + fatal(CRIT_FIRST + 41, "Trigger failed"); +} + + + +#ifdef WIN32 + + +trigger::trigger(bool autoreset, bool state) +{ + handle = CreateEvent(0, !autoreset, state, 0); + if (handle == 0) + trig_fail(); +} + + +#else + + +inline void trig_syscheck(int r) +{ + if (r != 0) + trig_fail(); +} + + +trigger::trigger(bool iautoreset, bool istate) + : state(int(istate)), autoreset(iautoreset) +{ + trig_syscheck(pthread_mutex_init(&mtx, 0)); + trig_syscheck(pthread_cond_init(&cond, 0)); +} + + +trigger::~trigger() +{ + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&mtx); +} + + +void trigger::wait() +{ + pthread_mutex_lock(&mtx); + while (state == 0) + pthread_cond_wait(&cond, &mtx); + if (autoreset) + state = 0; + pthread_mutex_unlock(&mtx); +} + + +void trigger::post() +{ + pthread_mutex_lock(&mtx); + state = 1; + if (autoreset) + pthread_cond_signal(&cond); + else + pthread_cond_broadcast(&cond); + pthread_mutex_unlock(&mtx); +} + + +void trigger::reset() +{ + state = 0; +} + + +#endif + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/ptypes_test.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ptypes_test.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,1622 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ +#include +#include + +#include "pport.h" +#include "ptypes.h" +#include "pstreams.h" +#include "pinet.h" +#include "ptime.h" + + +#ifndef PTYPES_ST +#include "pasync.h" +#endif + + +USING_PTYPES + + +void passert(bool cond) +{ + if (!cond) + { + fatal(0xa3, "*** ASSERTION FAILED ***"); + } +} + + +void showstr(const char* shouldbe, const char* is) +{ + passert(strcmp(shouldbe, is) == 0); + pout.putf("[%s] %s\n", shouldbe, is); +} + + +void showstr(const char* shouldbe, const string& is) +{ + showstr(shouldbe, pconst(is)); +} + + +void showhex(const char* shouldbe, const char* is, int islen) +{ + string s; + int i; + for (i = 0; i < islen; i++) + s += itostring((unsigned char)is[i], 16, 2); + s = lowercase(s); + showstr(shouldbe, s); +} + + +void showint(int shouldbe, int is) +{ + passert(shouldbe == is); + pout.putf("[%d] %d\n", shouldbe, is); +} + + +void showint(large shouldbe, large is) +{ + passert(shouldbe == is); + pout.putf("[%lld] %lld\n", shouldbe, is); +} + + +void showchar(char shouldbe, char is) +{ + passert(shouldbe == is); + pout.putf("[%c] %c\n", shouldbe, is); +} + + +// +// string test +// + + +void const_string_call(const string& s) +{ + showchar('R', s[2]); +} + + +void string_test1() +{ + pout.put("\n--- STRING CLASS\n"); + + static char strbuf[10] = "STRING"; + + char c = 'A'; + + string s1 = "string"; + s1 = s1; + s1 += s1; + del(s1, 6, 6); + string s2 = s1; + string s3; + string s4(strbuf, strlen(strbuf)); + string s5 = 'A'; + string s6 = c; + + showstr("string", s1); + showstr(s1, s2); + showstr("", s3); + showstr("STRING", s4); + const_string_call(s4); + showchar('I', s4[3]); + showint(6, length(s4)); + showint(2, refcount(s1)); + clear(s2); + showint(1, refcount(s1)); + s2 = s1; + unique(s1); + showint(1, refcount(s1)); + setlength(s1, 64); + string s7 = s1; + setlength(s1, 3); + showstr("str", s1); + showstr("strING", s1 += copy(s4, 3, 3)); + del(s1, 3, 3); + showstr("str", s1); + ins("ing", s1, 0); + showstr("ingstr", s1); + s2 = "str" + s1 + "ing"; + showstr("stringstring", s2); + s3 = s2; + s3 = "strungstrung"; + s3 = s2; + s3 = "strung"; + del(s3, 4); + showstr("stru", s3); + + s2 = "str" + s1; + s2 = s1 + "str"; + s2 += "str"; + + s2 = 's' + s1; + s2 = s1 + 's'; + s2 += 's'; + + s2 = c + s1; + s2 = s1 + c; + s2 += c; + + s2 = 'a'; + s2 = c; +} + + +void string_test2() +{ + pout.put("\n--- STRING CLASS\n"); + + string s1 = "ingstr"; + string s2 = "stringstring"; + string s4 = "STRING"; + + showint(1, pos('t', s2)); + showint(2, pos("ri", s2)); + showint(3, pos(s1, s2)); + showint(1, contains("tr", s2, 1)); + showint(0, contains("tr", s2, 2)); + showint(1, s4 == "STRING"); + showint(1, "STRING" == s4); + showchar('R', s4[2]); + + string s5 = 'A'; + showint(1, s5 == 'A'); + showint(1, 'A' == s5); + + showstr("123456789", itostring(123456789)); + showstr("123", itostring(char(123))); + showstr("-000123", itostring(-123, 10, 7, '0')); + showstr("0ABCDE", itostring(0xabcde, 16, 6)); + showstr("-9223372036854775808", itostring(LARGE_MIN)); + showstr("18446744073709551615", itostring(ULARGE_MAX)); + + showint(1234, (int)stringtoi("1234")); + showint(large(0x15AF), stringtoue("15AF", 16)); + showint(LARGE_MAX, stringtoue("5zzzzzzzzzz", 64)); + + try + { + // out of range by 1 + stringtoue("18446744073709551616", 10); + fatal(0xb0, "Conversion overflow not detected"); + } + catch (econv* e) + { + showstr("Out of range: '18446744073709551616'", e->get_message()); + delete e; + } + + showint(large(123), stringtoie("123")); + showint(large(-123), stringtoie("-123")); + showint(LARGE_MIN, stringtoie("-9223372036854775808")); + showint(LARGE_MAX, stringtoie("9223372036854775807")); + + try + { + // out of range by 1 + stringtoie("9223372036854775808"); + fatal(0xb0, "Conversion overflow not detected"); + } + catch (econv* e) + { + showstr("Out of range: '9223372036854775808'", e->get_message()); + delete e; + } + + showstr("abcabc", lowercase(s1 = "aBCAbc")); + showstr("abcabc", lowercase(s1)); +} + + +void string_benchmarks() +{ + pout.put("\n--- STRING BENCHMARKS\n"); + + int i; + string s1 = "string"; + string s2; + + // for the first time we run the test to let the VM settle down and stop swapping + for (i = 0; i < 156000; i++) + s2 += s1; + + // here is the actual test + clear(s2); + datetime start = now(); + for (i = 0; i < 156000; i++) + s2 += s1; + datetime diff = now() - start; + + pout.putf("Performance index compared to WinNT on P3/800MHz (smaller = better):\n%.3f\n", diff / 1000.0); +} + + +// +// cset test +// + +void cset_test() +{ + pout.put("\n--- CSET CLASS\n"); + + cset s1 = "~09~0a~0d~F0 A-Z~~"; + cset s2 = "A-F"; + char c = 'B'; + + showstr("~09~0a~0d A-Z~~~f0", asstring(s1)); + s1 -= char(0xf0); + s1 -= cset("~00-~20"); + showstr("A-Z~~", asstring(s1)); + s1 -= s2; + showstr("G-Z~~", asstring(s1)); + s1 += s2; + s1 += ' '; + showstr(" A-Z~~", asstring(s1)); + showint(1, s2 == cset("A-F")); + showint(1, s2 <= s1); + s1 -= 'A'; + s1 -= c; + showint(0, s2 <= s1); + s1 = s1 + char(0xf1); + showint(1, char(0xf1) & s1); + showint(0, char(0xf2) & s1); +} + + +// +// podlist +// + + +void const_podlist_test(const tpodlist& p) +{ +// int& i = p[0]; + showint(7, p[1]); +} + + +void podlist_test() +{ + pout.put("\n--- PODLIST\n"); + + tpodlist p; + p.add() = 6; + p.add(8); + p.ins(1, 7); + showint(7, p[1]); + const_podlist_test(p); + showint(3, p.get_count()); + p.set_count(5); + p.ins(5) = 10; + showint(10, p.top()); + p.pop(); + + tpodlist p1; + p1.add(p); + p1.pop(); + p1.add(p); +} + + +// +// ptrlist +// + + +struct known: public unknown +{ + int value; + known(int ivalue): value(ivalue) {} +}; + +typedef tobjlist knownlist; + + +string ol_asstring(const knownlist& s) +{ + string ret = "{"; + for (int i = 0; i < s.get_count(); i++) { + if (i > 0) + concat(ret, ", "); + ret += itostring(s[i]->value); + } + concat(ret, '}'); + return ret; +} + + +void ptrlist_test() +{ + pout.put("\n--- PTRLIST\n"); + + knownlist s1(true); + known* obj; + + s1.add(new known(10)); + s1.ins(0, new known(5)); + s1.ins(2, obj = new known(20)); + s1.add(new known(30)); + s1.add(new known(40)); + s1.put(4, new known(45)); + s1.del(4); + s1.del(1); + + s1[0]; + showint(3, s1.get_count()); + showint(1, s1.indexof(obj)); + showstr("{5, 20, 30}", ol_asstring(s1)); + + s1.clear(); + showstr("{}", ol_asstring(s1)); +} + + + +// +// strlist +// + + +typedef tstrlist knownstrlist; + + +string sl_asstring(const knownstrlist& s) +{ + string ret = "{"; + for (int i = 0; i < s.get_count(); i++) + { + if (i > 0) + concat(ret, ", "); + ret += s.getkey(i) + ":" + itostring(s[i]->value); + } + concat(ret, '}'); + return ret; +} + + +void strlist_test() +{ + pout.put("\n--- STRLIST\n"); + + knownstrlist s1(SL_OWNOBJECTS); + known* obj; + + s1.add("ten", new known(10)); + s1.ins(0, "five", new known(5)); + s1.ins(2, "twenty", obj = new known(20)); + s1.add("thirty", new known(30)); + s1.add("forty", new known(40)); + s1.put(4, "forty five", new known(45)); + s1.del(4); + s1.del(1); + + showint(3, s1.get_count()); + showint(1, s1.indexof(obj)); + showint(2, s1.indexof("thirty")); + showint(2, s1.indexof("THIRTY")); + showint(-1, s1.indexof("forty")); + + showstr("{five:5, twenty:20, thirty:30}", sl_asstring(s1)); + + knownstrlist s2(SL_OWNOBJECTS | SL_SORTED | SL_CASESENS); + s2.add("five", new known(5)); + s2.add("ten", new known(10)); + s2.add("twenty", new known(20)); + s2.add("thirty", new known(30)); + s2.add("forty", new known(40)); + + showint(5, s2.get_count()); + showint(3, s2.indexof("thirty")); + showint(-1, s2.indexof("THIRTY")); + showint(-1, s2.indexof("hovik")); + + showstr("{five:5, forty:40, ten:10, thirty:30, twenty:20}", sl_asstring(s2)); + + s2.clear(); + showstr("{}", sl_asstring(s2)); + + tstrlist s3(SL_OWNOBJECTS | SL_SORTED | SL_DUPLICATES); + + s3.add("a", nil); + s3.add("b", nil); + s3.add("b", nil); + s3.add("b", nil); + s3.add("b", nil); + s3.add("b", nil); + s3.add("b", nil); + s3.add("c", nil); + + showint(1, s3.indexof("b")); + s3.del(1, 2); + + tstrlist s(SL_OWNOBJECTS | SL_SORTED); + + s.put("five", new known(5)); + s.put("ten", new known(10)); + s.put("twenty", new known(20)); + s.put("thirty", new known(30)); + s.put("forty", new known(40)); + + showint(20, s["twenty"]->value); + showint(0, pintptr(s["hovik"])); + showint(5, s.get_count()); + s.put("twenty", nil); + showint(4, s.get_count()); +} + + +// +// textmap +// + + +void textmap_test() +{ + pout.put("\n--- TEXTMAP CLASS\n"); + + textmap c; + + c.put("name1", "value1"); + c.put("name2", "value2"); + c.put("name1", "value3"); + showstr("name2", c.getkey(1)); + c.put("name2", ""); + showint(1, c.get_count()); + showstr("value3", c["name1"]); + showstr("", c["name2"]); +} + + + +// +// streams +// + + +char buf1[] = "This is a test."; +char buf2[] = "The file should contain readable text."; + +const char* fname = "stmtest.txt"; + +void outfile_test() +{ + pout.put("\n--- OUTFILE CLASS\n"); + + showint(8, sizeof(off_t)); + + outfile f(fname, false); + f.set_umode(0600); + f.set_bufsize(3); + + f.open(); + f.put(buf1[0]); + f.put(buf1[1]); + f.put("is is a TEST."); + f.seek(-5, IO_END); + f.put("tes*/"); + f.seek(13); + f.put("t."); + f.puteol(); + f.close(); + + f.set_append(true); + f.open(); + f.write(buf2, strlen(buf2)); + f.puteol(); + f.close(); + + pnull.put("This should go to nowhere I"); + pnull.put("This should go to nowhere II"); +} + + +void infile_test() +{ + pout.put("\n--- INFILE CLASS\n"); + + compref f = &pin; + f = new infile(fname); + f->set_bufsize(3); + + char temp[4]; + + f->open(); + pout.putf("%c", f->get()); + pout.putf("%s\n", pconst(f->line())); + f->read(temp, sizeof temp - 1); + temp[sizeof temp - 1] = 0; + pout.putf("%s", temp); + f->get(); + f->putback(); + pout.putf("%s", pconst(f->token(cset("~20-~FF")))); + f->preview(); + if (f->get_eol()) + { + f->skipline(); + pout.put("\n"); + } + if (f->get_eof()) + pout.put("EOF\n"); +// f.error(1, "Test error message"); + +} + + +void mem_test() +{ + pout.put("\n--- OUT/IN MEMORY CLASS\n"); + + { + outmemory m(12); + m.open(); + m.put("MEMOry"); + m.put(" c"); + m.put("lass is working"); + m.seek(1); + m.put("emo"); + showstr("Memory class", m.get_strdata()); + // try reuse + m.open(); + m.put("memory"); + showstr("memory", m.get_strdata()); + } + { + inmemory m(""); + m.open(); + showstr("", m.token("*")); + m.set_strdata("gArbaGe"); + m.open(); + // try reuse + m.set_strdata("string strong"); + m.set_bufsize(2); // has no effect + m.open(); + showstr("string", m.token("a-z")); + m.seek(-6, IO_END); + showstr("strong", m.token("a-z")); + } +} + + +#ifndef PTYPES_ST + +// +// multithreading +// + +// +// rwlock test +// + +const int rw_max_threads = 30; +const int rw_max_tries = 30; +const int rw_max_delay = 20; +const int rw_rw_ratio = 5; +const bool rw_swap = false; + + +class rwthread: public thread +{ +protected: + virtual void execute(); +public: + rwthread(): thread(false) {} + virtual ~rwthread() { waitfor(); } +}; + + +rwlock rw; + +int reader_cnt = 0; +int writer_cnt = 0; +int total_writers = 0; +int total_readers = 0; +int max_readers = 0; + + +int prand(int max) +{ + return rand() % max; +} + + +void rwthread::execute() +{ + + for(int i = 0; i < rw_max_tries; i++) + { + psleep(prand(rw_max_delay)); + bool writer = prand(rw_rw_ratio) == 0; + if (writer ^ rw_swap) + { + rw.wrlock(); + pout.put('w'); + if (pincrement(&writer_cnt) > 1) + fatal(0xa0, "Writer: Huh?! Writers in here?"); + pincrement(&total_writers); + } + else + { + rw.rdlock(); + pout.put('.'); + int t; + if ((t = pincrement(&reader_cnt)) > max_readers) + max_readers = t; + if (writer_cnt > 0) + fatal(0xa1, "Reader: Huh?! Writers in here?"); + pincrement(&total_readers); + } + psleep(prand(rw_max_delay)); + if (writer ^ rw_swap) + pdecrement(&writer_cnt); + else + pdecrement(&reader_cnt); + rw.unlock(); + } +} + + + +void rwlock_test() +{ +// #ifdef __PTYPES_RWLOCK__ + pout.put("\n--- RWLOCK\n"); + + rwthread* threads[rw_max_threads]; + + srand((unsigned)time(0)); + + int i; + for(i = 0; i < rw_max_threads; i++) + { + threads[i] = new rwthread(); + threads[i]->start(); + } + for(i = 0; i < rw_max_threads; i++) + delete threads[i]; + + pout.putf("\nmax readers: %d\n", max_readers); + pout.putline("do writers 'starve'?"); +// #endif +} + + +// +// jobqueue test ---------------------------------------------------------- +// + + +const int MSG_MYJOB = MSG_USER + 1; +const int NUM_JOB_THREADS = 3; + + +class jobthread: public thread +{ +protected: + int id; + jobqueue* jq; + virtual void execute(); +public: + jobthread(int iid, jobqueue* ijq): thread(false), id(iid), jq(ijq) {} + ~jobthread() { waitfor(); } +}; + + +void jobthread::execute() +{ + bool quit = false; + while (!quit) + { + message* m = jq->getmessage(); + try + { + switch (m->id) + { + case MSG_MYJOB: + // ... do the job ... + psleep(prand(10)); + // report + pout.putf("Thread %d finished the job (param=%d)\n", id, m->param); + break; + case MSG_QUIT: + quit = true; + break; + } + } + catch(...) + { + // the message object must be freed! + delete m; + throw; + } + delete m; + } +} + + +void jobqueue_test() +{ + pout.put("\n--- JOBQUEUE\n"); + + jobqueue jq(3); + tobjlist threads(true); + + srand((unsigned)time(0)); + + // create the thread pool and start all threads + int i; + for(i = 0; i < NUM_JOB_THREADS; i++) + { + jobthread* j = new jobthread(i + 1, &jq); + j->start(); + threads.add(j); + } + + // post jobs for processing + jq.post(MSG_MYJOB, 1); + jq.post(MSG_MYJOB, 2); + jq.post(MSG_MYJOB, 3); + jq.post(MSG_MYJOB, 4); + jq.post(MSG_MYJOB, 5); + jq.post(MSG_MYJOB, 6); + jq.post(MSG_MYJOB, 7); + jq.post(MSG_MYJOB, 8); + + // terminate all threads + for(i = 0; i < NUM_JOB_THREADS; i++) + jq.post(MSG_QUIT); + + // threads are being waitfor()'ed and destroyed + // automatically by the list object +} + + + +// +// msgqueue test ---------------------------------------------------------- +// + + +const int MSG_DIAG = MSG_USER + 1; + + +// +// msgqueue test +// + +// +// class diagmessage +// + +class diagmessage: public message +{ +protected: + string module; + string diagstr; + friend class diagthread; +public: + diagmessage(string imodule, string idiagstr) + : message(MSG_DIAG), module(imodule), + diagstr(idiagstr) {} +}; + + +// +// class diagthread +// + +class diagthread: public thread, protected msgqueue +{ +protected: + virtual void execute(); // override thread::execute() + virtual void cleanup(); // override thread::cleanup() + virtual void msghandler(message& msg); // override msgqueue::msghandler() +public: + diagthread(): thread(false), msgqueue() { } + void postdiag(string module, string diagstr); + void postquit(); +}; + + +void diagthread::postdiag(string module, string diagstr) +{ + msgqueue::post(new diagmessage(module, diagstr)); +} + + +void diagthread::postquit() +{ + msgqueue::post(MSG_QUIT); +} + + +void diagthread::execute() +{ + // starts message queue processing; calls + // msghandler for each message + msgqueue::run(); +} + + +void diagthread::cleanup() +{ +} + + +void diagthread::msghandler(message& msg) +{ + switch (msg.id) + { + case MSG_DIAG: + { + diagmessage& m = (diagmessage&)msg; + pout.putf("%s: %s\n", pconst(m.module), pconst(m.diagstr)); + } + break; + default: + defhandler(msg); + } +} + + +// +// class testthread +// + + +class testthread: public thread +{ +protected: + diagthread* diag; + string myname; + virtual void execute(); + virtual void cleanup(); +public: + semaphore sem; + timedsem tsem; + testthread(diagthread* idiag) + : thread(false), diag(idiag), myname("testthread"), sem(0), tsem(0) {} +}; + + +void testthread::execute() +{ + diag->postdiag(myname, "starts and enters sleep for 1 second"); + psleep(1000); + diag->postdiag(myname, "signals the timed semaphore"); + tsem.post(); + diag->postdiag(myname, "releases the simple semaphore"); + sem.post(); + diag->postdiag(myname, "enters sleep for 1 more second"); + psleep(1000); +} + + +void testthread::cleanup() +{ + diag->postdiag(myname, "terminates"); +} + + +int thread_test() +{ + pout.put("\n--- THREAD AND SEMAPHORE CLASSES\n"); + + int v = 0; + showint(0, pexchange(&v, 5)); + showint(5, pexchange(&v, 10)); + + void* pv = 0; + passert(pexchange(&pv, &v) == 0); + passert(pexchange(&pv, 0) == &v); + + showint(11, pincrement(&v)); + showint(10, pdecrement(&v)); + + diagthread diag; + testthread thr(&diag); + + string myname = "main"; + + diag.start(); + thr.start(); + + diag.postdiag(myname, "waits 5 secs for the timed semaphore (actually wakes up after a second)"); + thr.tsem.wait(5000); // must exit after 1 second instead of 5 + + diag.postdiag(myname, "waits for the semaphore"); + thr.sem.wait(); + diag.postdiag(myname, "now waits for testthread to terminate"); + thr.waitfor(); + + diag.postquit(); + diag.waitfor(); + return 0; +} + + +// +// trigger test +// + + +class trigthread: public thread +{ +protected: + diagthread* diag; + string myname; + virtual void execute(); +public: + trigger trig; + trigthread(diagthread* idiag) + : thread(false), diag(idiag), myname("trigthread"), trig(true, false) {} + virtual ~trigthread() { waitfor(); } +}; + + +void trigthread::execute() +{ + diag->postdiag(myname, "waits on the trigger"); + trig.wait(); + + psleep(2000); + diag->postdiag(myname, "waits on the trigger"); + trig.wait(); + + diag->postdiag(myname, "terminates"); +} + + +int trigger_test() +{ + pout.put("\n--- TRIGGER\n"); + + diagthread diag; + trigthread thr(&diag); + + string myname = "main"; + + diag.start(); + thr.start(); + + psleep(1000); + diag.postdiag(myname, "posts the trigger"); + thr.trig.post(); + + psleep(1000); + diag.postdiag(myname, "posts the trigger again"); + thr.trig.post(); + + thr.waitfor(); + diag.postquit(); + diag.waitfor(); + return 0; +} + + + +#endif // PTYPES_ST + + +// +// md5 test +// + +static md5_digest digest; + +char* md5str(string data) +{ + outmd5 m; + m.open(); + m.put(data); + memcpy(digest, m.get_bindigest(), sizeof(md5_digest)); + return (char*)digest; +} + +string cryptpw(string username, string password) +{ + outmd5 m; + m.open(); + m.put(username); + m.put(password); + m.close(); + return m.get_digest(); +} + +void md5_test() +{ + pout.put("\n--- MD5 OUTPUT STREAM\n"); + // MD5 test suite from RFC1321 + showhex("d41d8cd98f00b204e9800998ecf8427e", md5str(""), md5_digsize); + showhex("0cc175b9c0f1b6a831c399e269772661", md5str("a"), md5_digsize); + showhex("900150983cd24fb0d6963f7d28e17f72", md5str("abc"), md5_digsize); + showhex("f96b697d7cb7938d525a2f31aaf161d0", md5str("message digest"), md5_digsize); + showhex("c3fcd3d76192e4007dfb496cca67e13b", md5str("abcdefghijklmnopqrstuvwxyz"), md5_digsize); + showhex("d174ab98d277d9f5a5611c2c9f419d9f", md5str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), md5_digsize); + showhex("57edf4a22be3c955ac49da2e2107b67a", md5str("12345678901234567890123456789012345678901234567890123456789012345678901234567890"), md5_digsize); + + showstr("t0htL.C9vunX8SPPsJjDmk", cryptpw("hovik", "myfavoritelonglonglongpassword")); +} + + +// +// outstm::putf() test +// + +void putf_test() +{ + pout.put("\n--- PUTF TEST\n"); + outmemory m; + m.open(); + + m.putf("%s, %c, %d, %llx", "string", 'A', 1234, large(-1)); + showstr("string, A, 1234, ffffffffffffffff", m.get_strdata()); + + m.open(); + + m.putf(" %%, %#o, %+010d", 0765, -3); + showstr(" %, 0765, -000000003", m.get_strdata()); +} + + +// +// pinet/socket tests +// + + +void inet_test1() +{ + try + { + pout.put("\n--- INET SOCKET & UTILITIES\n"); + + ipaddress ip(127, 0, 0, 1); + + // as a test target host we use the one that would never be down! :) + string testname = "www.apache.org"; + + ip = phostbyname(testname); + string ips = iptostring(ip); + pout.putf("IP address of %s: %s\n", pconst(testname), (ip == ipnone) ? "failed" : pconst(ips)); + + if (ip != ipnone) + { + string hs = phostbyaddr(ip); + pout.putf("Name of %s: %s\n", pconst(ips), pconst(hs)); + } + + pout.putf("Canonical name of your local www: %s\n", pconst(phostcname("www"))); + + testname = "www.melikyan.com"; + pout.putf("\nTrying %s:80...\n", pconst(testname)); + ipstream s(testname, 80); + + const char* request = + "GET /ptypes/test.txt HTTP/1.1\r\n" + "Accept: * /*\r\n" + "User-Agent: ptypes_test/2.1\r\n" + "Host: www.melikyan.com\r\n" + "Connection: close\r\n\r\n"; + + s.open(); + s.put(request); + s.flush(); + + while (!s.get_eof()) + { + char buf[16]; + int r = s.read(buf, sizeof(buf)); + pout.write(buf, r); + } + pout.put("\n"); + + s.close(); + } + catch(estream* e) + { + perr.putf("Socket error: %s\n", pconst(e->get_message())); + delete e; + } +} + + +#ifndef PTYPES_ST + + +const int testport = 8085; + + +class svthread: public thread, protected ipstmserver +{ +protected: + virtual void execute(); // override thread::execute() + virtual void cleanup(); // override thread::cleanup() +public: + svthread(): thread(false) {} + virtual ~svthread(); +}; + + +svthread::~svthread() +{ + waitfor(); +} + + +void svthread::execute() +{ + ipstream client; // a socket object to communicate with the client + + try + { + bindall(testport); // listen to all local addresses on port 8081 + serve(client); // wait infinitely for a connection request + + if (client.get_active()) + { + // read one line from the stream; note that theoretically the line can be long, + // so calling client.line(buf, sizeof(buf)) here is a much better idea + string req = lowercase(client.line()); + if (req == "hello") + { + // try to reverse-lookup the client's IP + string host = phostbyaddr(client.get_ip()); + if (isempty(host)) + host = iptostring(client.get_ip()); + + // now send our greeting to the client + client.putf("Hello, %s (%a), nice to see you!\n", + pconst(host), long(client.get_ip())); + client.flush(); + } + + // close() should be called explicitly to shut down the socket + // *gracefully*; otherwise ipstream's destructor may close the + // socket but in a less polite manner + client.close(); + } + } + catch(estream* e) + { + perr.putf("Server error: %s\n", pconst(e->get_message())); + delete e; + } + + // a real server could enter an infinite loop serving requests + // and producing separate threads for each connection +} + + +void svthread::cleanup() +{ +} + + +void inet_test2() +{ + pout.put("\n--- INET CLIENT/SERVER\n"); + + // we run the server in a separate thread in order to be able + // to imitate a client connection from the main thread + svthread server; + + pout.put("\nStarting the server thread...\n"); + server.start(); // it's that easy! :) + + // sleep some time to let the server start its job + psleep(1000); + + try + { + // now create a client socket and send a greeting to our server + ipstream client(ipaddress(127, 0, 0, 1), testport); + client.open(); + + pout.put("Sending a request to the server...\n"); + client.putline("Hello"); + client.flush(); + string rsp = client.line(); + pout.putf("Received: %s\n", pconst(rsp)); + pout.putf("My address and port: %s:%d\n", + pconst(iptostring(client.get_myip())), client.get_myport()); + + client.close(); + } + catch(estream* e) + { + perr.putf("Error: %s\n", pconst(e->get_message())); + delete e; + } + +} + + +// +// UDP test +// + + +class msgsvthread: public thread +{ +protected: + void execute(); +public: + msgsvthread(): thread(false) {} + virtual ~msgsvthread() { waitfor(); } +}; + + +void msgsvthread::execute() +{ + ipmsgserver s; + s.bindall(testport); + try + { + string req = s.receive(1024); + pout.putf("Server received: %s\n", pconst(req)); + string rsp = "gotcha"; + s.send(rsp); + } + catch(estream* e) + { + perr.putf("Server error: %s\n", pconst(e->get_message())); + delete e; + } +} + + +void inet_test3() +{ + pout.put("\n--- INET MESSAGE CLIENT/SERVER\n"); + + msgsvthread sv; + sv.start(); + psleep(1000); + + ipmessage m(ipbcast /* ipaddress(127, 0, 0, 1) */, testport); + try + { + string msg = "hello"; + m.send(msg); + string rsp = m.receive(1024); + pout.putf("Client received: %s\n", pconst(rsp)); + } + catch(estream* e) + { + perr.putf("Client error: %s\n", pconst(e->get_message())); + delete e; + } +} + + +// +// named pipes test +// + + +#define TEST_PIPE "ptypes.test" + + +class npthread: public thread, protected npserver +{ +protected: + virtual void execute(); + virtual void cleanup(); +public: + npthread(): thread(false), npserver(TEST_PIPE) {} + virtual ~npthread(); +}; + + +npthread::~npthread() +{ + waitfor(); +} + + +void npthread::execute() +{ + namedpipe client; + + try + { + serve(client); + + if (client.get_active()) + { + string req = lowercase(client.line()); + if (req == "hello") + { + client.putline("Hello, nice to see you!"); + client.flush(); + } + + client.close(); + } + } + catch(estream* e) + { + perr.putf("Pipe server error: %s\n", pconst(e->get_message())); + delete e; + } +} + + +void npthread::cleanup() +{ +} + + +void pipe_test() +{ + npthread server; + + pout.put("\n--- NAMED PIPES\n"); + pout.put("Starting the pipe server thread...\n"); + server.start(); + + psleep(1000); + + namedpipe client(TEST_PIPE); + + try + { + client.open(); + + pout.put("Sending a request to the server...\n"); + client.putline("Hello"); + client.flush(); + string rsp = client.line(); + pout.putf("Received: %s\n", pconst(rsp)); + + client.close(); + } + catch(estream* e) + { + perr.putf("Error: %s\n", pconst(e->get_message())); + delete e; + } +} + + +#endif // PTYPES_ST + + +// +// date/time/calendar +// + + +void time_test() +{ + pout.put("\n--- DATE/TIME/CALENDAR\n"); + + tzupdate(); + + int year, month, day; + datetime d = encodedate(9999, 12, 31); + decodedate(d, year, month, day); + d = encodedate(1970, 1, 1); + decodedate(d, year, month, day); + + datetime dt; + dt = invdatetime; + int hour, min, sec, msec; + dt = encodetime(23, 59, 59, 998); + decodetime(dt, hour, min, sec, msec); + + dt = encodedate(2001, 8, 27) + encodetime(14, 33, 10); + d = encodedate(2001, 8, 28) + encodetime(14, 33, 10, 500); + dayofweek(dt); + + dt = now(false); + pout.putf("Local time: %s\n", pconst(dttostring(dt, "%x %X %Z"))); + datetime utc = now(); + pout.putf("UTC time: %t GMT\n", utc); + + time_t ut; + time(&ut); + pout.putline(dttostring(utodatetime(ut), "%c")); + + int t = tzoffset(); + bool neg = t < 0; + if (neg) + t = -t; + pout.putf("Time zone offset: %c%02d%02d\n", neg ? '-' : '+', t / 60, t % 60); + { + // PTypes' birthday (birth moment, if you wish) + datetime d = encodedate(2000, 3, 30) + encodetime(13, 24, 58, 995); + pout.putf("PTypes' birth moment: %T GMT\n", d); + + // now see how old is PTypes in days, hours, minutes, etc + datetime diff = now() - d; + int hours, mins, secs, msecs; + decodetime(diff, hours, mins, secs, msecs); + pout.putf("PTypes' life time: %d days %d hours %d minutes %d seconds and %d milliseconds\n", + days(diff), hours, mins, secs, msecs); + +#ifndef PTYPES_ST + // measure the difference in milliseconds between two calls to now() + datetime m = now(); + psleep(17); // sleep for 17 milliseconds + pout.putf("A 17 millisecond dream lasted actually %d milliseconds\n", int(now() - m)); + // this will show the actual precision of the clock on the given platform; + // Windows, f.ex., always shows the difference in 10 msec increments +#endif + } +} + + +// +// streams documentation example #2 +// + + +const cset letters("_A-Za-z"); +const cset digits("0-9"); +const cset identchars = letters + digits; +const cset otherchars = !letters; + + +void doc_example() +{ + tstrlist dic(SL_SORTED); + + infile f("../src/ptypes_test.cxx"); + + try + { + f.open(); + + while (!f.get_eof()) + { + char c = f.preview(); + + // a C identifier starts with a letter + if (c & letters) + { + // ... and may contain letters and digits + string ident = f.token(identchars); + int i; + if (!dic.search(ident, i)) + dic.add(ident, 0); + } + + else + f.skiptoken(otherchars); + } + + } + + catch (estream* e) + { + pout.putf("Error: %s\n", pconst(e->get_message())); + delete e; + } + + // now print the dictionary + for (int i = 0; i < dic.get_count(); i++) + pout.putline(dic.getkey(i)); +} + + +// +// variant +// + + +void variant_test() +{ + pout.put("\n--- VARIANT\n"); + + variant v0 = 'A'; + variant v1 = short(33); + variant v2 = "456"; + variant v3 = int(v1) + int(v2); + variant v4 = string(v1) + " cows"; + string s = string(v4); +// s = v4; + variant v5 = new component(); + variant v6; + + put(v6, 291, v1); + put(v6, "key", v2); + put(v6, "another-key", "another-value"); + showstr("33 cows", string(v4)); + showint(456, v6["key"]); + showstr("33", string(v1)); + showint(1, bool(v6)); + v2 = aclone(v6); + v5 = v6; + + variant vi; + int i; + for (i = 0; anext(v6, i, vi);) + pout.putf("%d\n", int(vi)); + + variant v7; + aadd(v7, v1); + aadd(v7, v3); + aadd(v7, v4); + adel(v7, 2); + for (i = 0; i < alength(v7); i++) + pout.putf("%s\n", pconst(string(aget(v7, i)))); +} + + +// +// main +// + + +int main() +{ + try + { + string_test1(); + string_test2(); + string_benchmarks(); + cset_test(); + + podlist_test(); + ptrlist_test(); + strlist_test(); + textmap_test(); +variant_test(); + outfile_test(); + infile_test(); + mem_test(); + md5_test(); + putf_test(); + + time_test(); + + + inet_test1(); + +#ifndef PTYPES_ST + pipe_test(); + + jobqueue_test(); + thread_test(); + rwlock_test(); + trigger_test(); + + inet_test2(); + inet_test3(); +#endif + + } + + catch (estream* e) + { + perr.putf("\nError: %s\n", pconst(e->get_message())); + exit(1); + delete e; + } + +#ifdef DEBUG + if (stralloc != 0 || objalloc != 0) + { + perr.putf("DBG stralloc: %d, objalloc: %d\n", stralloc, objalloc); + fatal(255, "Allocation problems"); + } +#endif + + return 0; +} + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/punit.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/punit.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,176 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "ptypes.h" +#include "pasync.h" +#include "pstreams.h" + +#ifdef WIN32 +# include +#else +# include +#endif + + +PTYPES_BEGIN + + +// +// internal thread class for running units asynchronously +// + +class unit_thread: public thread +{ +protected: + unit* target; + virtual void execute(); +public: + unit_thread(unit* itarget); + virtual ~unit_thread(); +}; + + +unit_thread::unit_thread(unit* itarget) + : thread(false), target(itarget) +{ + start(); +} + + + +unit_thread::~unit_thread() +{ + waitfor(); +} + + +void unit_thread::execute() +{ + target->do_main(); +} + + +// +// unit class +// + +unit::unit() + : component(), pipe_next(nil), main_thread(nil), + running(0), uin(&pin), uout(&pout) +{ +} + + +unit::~unit() +{ + delete tpexchange(&main_thread, nil); +} + + +int unit::classid() +{ + return CLASS_UNIT; +} + + +void unit::main() +{ +} + + +void unit::cleanup() +{ +} + + +void unit::do_main() +{ + try + { + if (!uout->get_active()) + uout->open(); + if (!uin->get_active()) + uin->open(); + main(); + if (uout->get_active()) + uout->flush(); + } + catch(exception* e) + { + perr.putf("Error: %s\n", pconst(e->get_message())); + delete e; + } + + try + { + cleanup(); + } + catch(exception* e) + { + perr.putf("Error: %s\n", pconst(e->get_message())); + delete e; + } + + if (pipe_next != nil) + uout->close(); +} + + +void unit::connect(unit* next) +{ + waitfor(); + pipe_next = next; + infile* in = new infile(); + outfile* out = new outfile(); + next->uin = in; + uout = out; + in->pipe(*out); +} + + +void unit::waitfor() +{ + if (running == 0) + return; + delete tpexchange(&main_thread, nil); + unit* next = tpexchange(&pipe_next, nil); + if (next != nil) + { + next->waitfor(); + next->uin = &pin; + } + uout = &pout; + running = 0; +} + + +void unit::run(bool async) +{ + if (pexchange(&running, 1) != 0) + return; + + if (main_thread != nil) + fatal(CRIT_FIRST + 60, "Unit already running"); + + if (pipe_next != nil) + pipe_next->run(true); + + if (async) + main_thread = new unit_thread(this); + else + { + do_main(); + waitfor(); + } +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/punknown.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/punknown.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,21 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "ptypes.h" + + +PTYPES_BEGIN + + +int objalloc = 0; + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pvariant.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pvariant.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,664 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + + +#include +#include +#include + +#include "ptypes.h" + + +PTYPES_BEGIN + + +const variant nullvar; + + +struct _varitem +{ + string key; + variant var; + + _varitem(const string& ikey, const variant& ivar): key(ikey), var(ivar) {} +}; +typedef _varitem* pvaritem; + + +class ptpublic _varray: protected tobjlist<_varitem> +{ +protected: + int refcount; + + virtual int compare(const void* key, const void* item) const; + + friend class variant; + +public: + _varray(); + _varray(const _varray& a); + virtual ~_varray(); + + int get_count() { return tobjlist<_varitem>::get_count(); } + void clear() { tobjlist<_varitem>::clear(); } + void pack() { tobjlist<_varitem>::pack(); } + _varitem* doget(int index) const { return tobjlist<_varitem>::doget(index); } + const variant& get(int index) const { if (unsigned(index) < unsigned(count)) return doget(index)->var; else return nullvar; } + const string& getkey(int index) const { if (unsigned(index) < unsigned(count)) return doget(index)->key; else return nullstring; } + const variant& get(const char* key) const; + int put(const string& key, const variant& var); + void put(int index, const variant& var) { if (unsigned(index) < unsigned(count)) doget(index)->var = var; } + void ins(int index, const variant& var) { if (unsigned(index) < unsigned(count)) doins(index, new _varitem(nullstring, var)); } + int addvar(const variant& var); + void del(int index) { if (unsigned(index) < unsigned(count)) dodel(index); } + void del(const string& key) { put(key, nullstring); } +}; +typedef _varray* pvarray; + + +_varray::_varray() + : tobjlist<_varitem>(true), refcount(0) +{ + config.sorted = true; + config.casesens = true; +} + + +_varray::_varray(const _varray& a) + : tobjlist<_varitem>(true), refcount(0) +{ + config.sorted = true; + config.casesens = true; + set_capacity(a.count); + for (int i = 0; i < a.count; i++) + { + _varitem* v = a.doget(i); + doins(i, new _varitem(v->key, v->var)); + } +} + + +_varray::~_varray() +{ +} + + +int _varray::compare(const void* key, const void* item) const +{ + if (config.casesens) + return strcmp(pconst(key), pvaritem(item)->key); + else + return strcasecmp(pconst(key), pvaritem(item)->key); +} + + +const variant& _varray::get(const char* key) const +{ + int index; + if (search(key, index)) + return doget(index)->var; + else + return nullvar; +} + + +int _varray::put(const string& key, const variant& var) +{ + int index; + if (search(pconst(key), index)) + { + if (isnull(var)) + dodel(index); + else + doget(index)->var = var; + } + else if (!isnull(var)) + doins(index, new _varitem(key, var)); + return index; +} + + +int _varray::addvar(const variant& v) +{ + int i; + if (count > 0 && isempty(doget(count - 1)->key)) + i = count; + else + i = 0; + doins(i, new _varitem(nullstring, v)); + return i; +} + + +static void vconverr(large v); + + +static void vfatal() +{ + fatal(CRIT_FIRST + 60, "Variant data corrupt"); +} + + +evariant::~evariant() +{ +} + + +void variant::initialize(_varray* a) +{ + tag = VAR_ARRAY; +#ifdef PTYPES_ST + a->refcount++; +#else + pincrement(&a->refcount); +#endif + value.a = a; +} + + +void variant::initialize(component* o) +{ + tag = VAR_OBJECT; + value.o = addref(o); +} + + +void variant::initialize(const variant& v) +{ + switch (v.tag) + { + case VAR_NULL: + tag = VAR_NULL; + break; + case VAR_INT: + case VAR_BOOL: + case VAR_FLOAT: + tag = v.tag; + value = v.value; + break; + case VAR_STRING: + initialize(PTR_TO_STRING(v.value.s)); + break; + case VAR_ARRAY: + initialize(v.value.a); + break; + case VAR_OBJECT: + initialize(v.value.o); + break; + default: + vfatal(); + } +} + + +void variant::finalize() +{ + if (tag >= VAR_COMPOUND) + { + switch (tag) + { + case VAR_STRING: + PTYPES_NAMESPACE::finalize(PTR_TO_STRING(value.s)); + break; + case VAR_ARRAY: +#ifdef PTYPES_ST + if (--value.a->refcount == 0) +#else + if (pdecrement(&value.a->refcount) == 0) +#endif + delete value.a; + break; + case VAR_OBJECT: + release(value.o); + break; + default: + vfatal(); + } + } + tag = VAR_NULL; +} + + +void variant::assign(large v) { finalize(); initialize(v); } +void variant::assign(bool v) { finalize(); initialize(v); } +void variant::assign(double v) { finalize(); initialize(v); } +void variant::assign(const char* v) { finalize(); initialize(v); } + + +void variant::assign(const string& v) +{ + if (tag == VAR_STRING) + PTR_TO_STRING(value.s) = v; + else + { + finalize(); + initialize(v); + } +} + + +void variant::assign(_varray* a) +{ + if (tag == VAR_ARRAY && value.a == a) + return; + finalize(); + initialize(a); +} + + +void variant::assign(component* o) +{ + if (tag == VAR_OBJECT) + { + if (value.o == o) + return; + else + release(value.o); + } + else + finalize(); + initialize(o); +} + + +void variant::assign(const variant& v) +{ + switch (v.tag) + { + case VAR_NULL: + finalize(); + tag = VAR_NULL; + break; + case VAR_INT: + case VAR_BOOL: + case VAR_FLOAT: + finalize(); + tag = v.tag; + value = v.value; + break; + case VAR_STRING: + assign(PTR_TO_STRING(v.value.s)); + break; + case VAR_ARRAY: + assign(v.value.a); + break; + case VAR_OBJECT: + assign(v.value.o); + break; + default: + vfatal(); + } +} + + +void ptdecl clear(variant& v) +{ + v.finalize(); + v.initialize(); +} + + +variant::operator int() const +{ + large t = operator large(); + if (t < INT_MIN || t > INT_MAX) + vconverr(t); + return int(t); +} + + +variant::operator unsigned int() const +{ + large t = operator large(); + if (t < 0 || t > UINT_MAX) + vconverr(t); + return uint(t); +} + + +variant::operator long() const +{ + large t = operator large(); + if (t < LONG_MIN || t > LONG_MAX) + vconverr(t); + return int(t); +} + + +variant::operator unsigned long() const +{ + large t = operator large(); + if (t < 0 || t > large(ULONG_MAX)) + vconverr(t); + return uint(t); +} + + +variant::operator large() const +{ + switch(tag) + { + case VAR_NULL: return 0; + case VAR_INT: return value.i; + case VAR_BOOL: return int(value.b); + case VAR_FLOAT: return int(value.f); + case VAR_STRING: + { + const char* p = PTR_TO_STRING(value.s); + bool neg = *p == '-'; + if (neg) + p++; + large t = stringtoi(p); + if (t < 0) + return 0; + else + return neg ? -t : t; + } + case VAR_ARRAY: return value.a->count != 0; + case VAR_OBJECT: return 0; + default: vfatal(); + } + return 0; +} + + +variant::operator bool() const +{ + switch(tag) + { + case VAR_NULL: return false; + case VAR_INT: return value.i != 0; + case VAR_BOOL: return value.b; + case VAR_FLOAT: return value.f != 0; + case VAR_STRING: return !isempty((PTR_TO_STRING(value.s))); + case VAR_ARRAY: return value.a->count != 0; + case VAR_OBJECT: return value.o != nil; + default: vfatal(); + } + return false; +} + + +variant::operator double() const +{ + switch(tag) + { + case VAR_NULL: return 0; + case VAR_INT: return double(value.i); + case VAR_BOOL: return int(value.b); + case VAR_FLOAT: return value.f; + case VAR_STRING: + { + char* e; + double t = strtod(PTR_TO_STRING(value.s), &e); + if (*e != 0) + return 0; + else + return t; + } + case VAR_ARRAY: return int(value.a->count != 0); + case VAR_OBJECT: return 0; + default: vfatal(); + } + return 0; +} + + +void string::initialize(const variant& v) +{ + switch(v.tag) + { + case VAR_NULL: initialize(); break; + case VAR_INT: initialize(itostring(v.value.i)); break; + case VAR_BOOL: if (v.value.b) initialize('1'); else initialize('0'); break; + case VAR_FLOAT: + { + char buf[256]; + sprintf(buf, "%g", v.value.f); + initialize(buf); + } + break; + case VAR_STRING: initialize(PTR_TO_STRING(v.value.s)); break; + case VAR_ARRAY: initialize(); break; + case VAR_OBJECT: initialize(); break; + default: vfatal(); + } +} + + +variant::operator string() const +{ + // this is a 'dirty' solution to gcc 3.3 typecast problem. most compilers + // handle variant::operator string() pretty well, while gcc 3.3 requires + // to explicitly declare a constructor string::string(const variant&). + // ironically, the presence of both the typecast operator and the constructor + // confuses the MSVC compiler. so the only thing we can do to please all + // those compilers [that "move towards the c++ standard"] is to conditionally + // exclude the constructor string(const variant&). and this is not the whole + // story. i see you are bored with it and i let you go. nobody would ever care + // about this. it just works, though i'm not happy with what i wrote here: + string t; + t.initialize(*this); + return t; +} + + +variant::operator component*() const +{ + if (tag == VAR_OBJECT) + return value.o; + else + return nil; +} + + +bool variant::equal(const variant& v) const +{ + if (tag != v.tag) + return false; + switch (tag) + { + case VAR_NULL: return true; + case VAR_INT: return value.i == v.value.i; + case VAR_BOOL: return value.b == v.value.b; + case VAR_FLOAT: return value.f == v.value.f; + case VAR_STRING: return strcmp(value.s, v.value.s) == 0; + case VAR_ARRAY: return value.a == v.value.a; + case VAR_OBJECT: return value.o == v.value.o; + default: vfatal(); return false; + } +} + + +static string numkey(large key) +{ + return itostring(key, 16, 16, '0'); +} + + +void ptdecl aclear(variant& v) +{ + if (v.tag == VAR_ARRAY) + v.value.a->clear(); + else + { + v.finalize(); + v.initialize(new _varray()); + } +} + + +void ptdecl apack(variant& v) +{ + if (v.tag == VAR_ARRAY) + v.value.a->pack(); +} + + +variant ptdecl aclone(const variant& v) +{ + if (v.tag == VAR_ARRAY) + return variant(new _varray(*(v.value.a))); + else + return variant(new _varray()); +} + + +int ptdecl alength(const variant& v) +{ + if (v.tag == VAR_ARRAY) + return v.value.a->get_count(); + else + return 0; +} + + +const variant& ptdecl get(const variant& v, const string& key) +{ + if (v.tag == VAR_ARRAY) + return v.value.a->get(key); + else + return nullvar; +} + + +const variant& ptdecl get(const variant& v, large key) +{ + return get(v, numkey(key)); +} + + +void ptdecl put(variant& v, const string& key, const variant& item) +{ + if (v.tag != VAR_ARRAY) + aclear(v); + v.value.a->put(key, item); +} + + +void ptdecl put(variant& v, large key, const variant& item) +{ + put(v, numkey(key), item); +} + + +void ptdecl del(variant& v, const string& key) +{ + if (v.tag == VAR_ARRAY) + v.value.a->del(key); +} + + +void ptdecl del(variant& v, large key) +{ + del(v, numkey(key)); +} + + +bool ptdecl anext(const variant& array, int& index, variant& item) +{ + string key; + return anext(array, index, item, key); +} + + +bool ptdecl anext(const variant& array, int& index, variant& item, string & key) +{ + if (array.tag != VAR_ARRAY) + { + clear(item); + return false; + } + if (index < 0 || index >= array.value.a->get_count()) + { + clear(item); + return false; + } + item = array.value.a->doget(index)->var; + key = array.value.a->doget(index)->key; + index++; + return true; +} + +bool ptdecl anext(const variant& array, int& index, variant& item, variant & key) +{ + if (array.tag != VAR_ARRAY) + { + clear(item); + return false; + } + if (index < 0 || index >= array.value.a->get_count()) + { + clear(item); + return false; + } + item = array.value.a->doget(index)->var; + key = array.value.a->doget(index)->key; + index++; + return true; +} + +void ptdecl add(variant & v, const variant & var) +{ + put(v, alength(v), var); +} + + +int ptdecl aadd(variant& array, const variant& item) +{ + if (array.tag != VAR_ARRAY) + aclear(array); + return array.value.a->addvar(item); +} + + +const variant& ptdecl aget(const variant& array, int index) +{ + if (array.tag == VAR_ARRAY) + return array.value.a->get(index); + else + return nullvar; +} + + +void ptdecl adel(variant& array, int index) +{ + if (array.tag == VAR_ARRAY) + array.value.a->del(index); +} + + +void ptdecl aput(variant& array, int index, const variant& item) +{ + if (array.tag == VAR_ARRAY) + array.value.a->put(index, item); +} + + +void ptdecl ains(variant& array, int index, const variant& item) +{ + if (array.tag == VAR_ARRAY) + array.value.a->ins(index, item); +} + + +#ifdef _MSC_VER +// disable "unreachable code" warning for throw (known compiler bug) +# pragma warning (disable: 4702) +#endif + +static void vconverr(large v) +{ + throw new evariant("Value out of range: " + itostring(v)); +} + + +PTYPES_END diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 src/pversion.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pversion.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,15 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "pport.h" + +unsigned long __ptypes_version = 0x00020101; + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes.opensdf Binary file win32/PTypes.opensdf has changed diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes.sdf Binary file win32/PTypes.sdf has changed diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes.sln --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes.sln Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PTypes_DLL", "PTypes_DLL.vcxproj", "{181E52DE-3CF7-425B-B24A-E59711635486}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PTypes_Lib", "PTypes_Lib.vcxproj", "{4A435BFE-D414-4FFA-8364-672A2B7FFF01}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PTypes_Lib_ST", "PTypes_Lib_ST.vcxproj", "{FB3CDEFD-B016-4EFE-8634-86083A584B04}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PTypes_Test", "PTypes_Test.vcxproj", "{A08093B3-4E89-4D19-85FD-D0679E7DC4EA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PTypes_Test_ST", "PTypes_Test_ST.vcxproj", "{ADC21731-3254-476F-8D37-8266E1EC293D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wshare", "wshare.vcxproj", "{6B53FB0A-5052-4A7B-8419-7CBF117088EB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {181E52DE-3CF7-425B-B24A-E59711635486}.Debug|Win32.ActiveCfg = Debug|Win32 + {181E52DE-3CF7-425B-B24A-E59711635486}.Debug|Win32.Build.0 = Debug|Win32 + {181E52DE-3CF7-425B-B24A-E59711635486}.Release|Win32.ActiveCfg = Release|Win32 + {181E52DE-3CF7-425B-B24A-E59711635486}.Release|Win32.Build.0 = Release|Win32 + {4A435BFE-D414-4FFA-8364-672A2B7FFF01}.Debug|Win32.ActiveCfg = Debug|Win32 + {4A435BFE-D414-4FFA-8364-672A2B7FFF01}.Debug|Win32.Build.0 = Debug|Win32 + {4A435BFE-D414-4FFA-8364-672A2B7FFF01}.Release|Win32.ActiveCfg = Release|Win32 + {4A435BFE-D414-4FFA-8364-672A2B7FFF01}.Release|Win32.Build.0 = Release|Win32 + {FB3CDEFD-B016-4EFE-8634-86083A584B04}.Debug|Win32.ActiveCfg = Debug|Win32 + {FB3CDEFD-B016-4EFE-8634-86083A584B04}.Debug|Win32.Build.0 = Debug|Win32 + {FB3CDEFD-B016-4EFE-8634-86083A584B04}.Release|Win32.ActiveCfg = Release|Win32 + {FB3CDEFD-B016-4EFE-8634-86083A584B04}.Release|Win32.Build.0 = Release|Win32 + {A08093B3-4E89-4D19-85FD-D0679E7DC4EA}.Debug|Win32.ActiveCfg = Debug|Win32 + {A08093B3-4E89-4D19-85FD-D0679E7DC4EA}.Debug|Win32.Build.0 = Debug|Win32 + {A08093B3-4E89-4D19-85FD-D0679E7DC4EA}.Release|Win32.ActiveCfg = Release|Win32 + {A08093B3-4E89-4D19-85FD-D0679E7DC4EA}.Release|Win32.Build.0 = Release|Win32 + {ADC21731-3254-476F-8D37-8266E1EC293D}.Debug|Win32.ActiveCfg = Debug|Win32 + {ADC21731-3254-476F-8D37-8266E1EC293D}.Debug|Win32.Build.0 = Debug|Win32 + {ADC21731-3254-476F-8D37-8266E1EC293D}.Release|Win32.ActiveCfg = Release|Win32 + {ADC21731-3254-476F-8D37-8266E1EC293D}.Release|Win32.Build.0 = Release|Win32 + {6B53FB0A-5052-4A7B-8419-7CBF117088EB}.Debug|Win32.ActiveCfg = Debug|Win32 + {6B53FB0A-5052-4A7B-8419-7CBF117088EB}.Debug|Win32.Build.0 = Debug|Win32 + {6B53FB0A-5052-4A7B-8419-7CBF117088EB}.Release|Win32.ActiveCfg = Release|Win32 + {6B53FB0A-5052-4A7B-8419-7CBF117088EB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes.sln.old --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes.sln.old Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,59 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PTypes_DLL", "PTypes_DLL.vcproj", "{181E52DE-3CF7-425B-B24A-E59711635486}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PTypes_Lib", "PTypes_Lib.vcproj", "{4A435BFE-D414-4FFA-8364-672A2B7FFF01}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PTypes_Lib_ST", "PTypes_Lib_ST.vcproj", "{FB3CDEFD-B016-4EFE-8634-86083A584B04}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PTypes_Test", "PTypes_Test.vcproj", "{A08093B3-4E89-4D19-85FD-D0679E7DC4EA}" + ProjectSection(ProjectDependencies) = postProject + {181E52DE-3CF7-425B-B24A-E59711635486} = {181E52DE-3CF7-425B-B24A-E59711635486} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PTypes_Test_ST", "PTypes_Test_ST.vcproj", "{ADC21731-3254-476F-8D37-8266E1EC293D}" + ProjectSection(ProjectDependencies) = postProject + {FB3CDEFD-B016-4EFE-8634-86083A584B04} = {FB3CDEFD-B016-4EFE-8634-86083A584B04} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wshare", "wshare.vcproj", "{6B53FB0A-5052-4A7B-8419-7CBF117088EB}" + ProjectSection(ProjectDependencies) = postProject + {4A435BFE-D414-4FFA-8364-672A2B7FFF01} = {4A435BFE-D414-4FFA-8364-672A2B7FFF01} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {181E52DE-3CF7-425B-B24A-E59711635486}.Debug|Win32.ActiveCfg = Debug|Win32 + {181E52DE-3CF7-425B-B24A-E59711635486}.Debug|Win32.Build.0 = Debug|Win32 + {181E52DE-3CF7-425B-B24A-E59711635486}.Release|Win32.ActiveCfg = Release|Win32 + {181E52DE-3CF7-425B-B24A-E59711635486}.Release|Win32.Build.0 = Release|Win32 + {4A435BFE-D414-4FFA-8364-672A2B7FFF01}.Debug|Win32.ActiveCfg = Debug|Win32 + {4A435BFE-D414-4FFA-8364-672A2B7FFF01}.Debug|Win32.Build.0 = Debug|Win32 + {4A435BFE-D414-4FFA-8364-672A2B7FFF01}.Release|Win32.ActiveCfg = Release|Win32 + {4A435BFE-D414-4FFA-8364-672A2B7FFF01}.Release|Win32.Build.0 = Release|Win32 + {FB3CDEFD-B016-4EFE-8634-86083A584B04}.Debug|Win32.ActiveCfg = Debug|Win32 + {FB3CDEFD-B016-4EFE-8634-86083A584B04}.Debug|Win32.Build.0 = Debug|Win32 + {FB3CDEFD-B016-4EFE-8634-86083A584B04}.Release|Win32.ActiveCfg = Release|Win32 + {FB3CDEFD-B016-4EFE-8634-86083A584B04}.Release|Win32.Build.0 = Release|Win32 + {A08093B3-4E89-4D19-85FD-D0679E7DC4EA}.Debug|Win32.ActiveCfg = Debug|Win32 + {A08093B3-4E89-4D19-85FD-D0679E7DC4EA}.Debug|Win32.Build.0 = Debug|Win32 + {A08093B3-4E89-4D19-85FD-D0679E7DC4EA}.Release|Win32.ActiveCfg = Release|Win32 + {A08093B3-4E89-4D19-85FD-D0679E7DC4EA}.Release|Win32.Build.0 = Release|Win32 + {ADC21731-3254-476F-8D37-8266E1EC293D}.Debug|Win32.ActiveCfg = Debug|Win32 + {ADC21731-3254-476F-8D37-8266E1EC293D}.Debug|Win32.Build.0 = Debug|Win32 + {ADC21731-3254-476F-8D37-8266E1EC293D}.Release|Win32.ActiveCfg = Release|Win32 + {ADC21731-3254-476F-8D37-8266E1EC293D}.Release|Win32.Build.0 = Release|Win32 + {6B53FB0A-5052-4A7B-8419-7CBF117088EB}.Debug|Win32.ActiveCfg = Debug|Win32 + {6B53FB0A-5052-4A7B-8419-7CBF117088EB}.Debug|Win32.Build.0 = Debug|Win32 + {6B53FB0A-5052-4A7B-8419-7CBF117088EB}.Release|Win32.ActiveCfg = Release|Win32 + {6B53FB0A-5052-4A7B-8419-7CBF117088EB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_DLL.vcproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_DLL.vcproj Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,1461 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_DLL.vcxproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_DLL.vcxproj Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,489 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {181E52DE-3CF7-425B-B24A-E59711635486} + + + + DynamicLibrary + false + MultiByte + + + DynamicLibrary + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + .\DLL_Debug\ + .\DLL_Debug\ + false + .\DLL_Release\ + .\DLL_Release\ + false + AllRules.ruleset + + + AllRules.ruleset + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\DLL_Debug/PTypes_DLL.tlb + + + + + Disabled + ../include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;PTYPES_DLL_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + .\DLL_Debug/PTypes_DLL.pch + .\DLL_Debug/ + .\DLL_Debug/ + .\DLL_Debug/ + true + Level4 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0417 + + + ws2_32.lib;%(AdditionalDependencies) + DLL_Debug/ptypes21.dll + true + true + .\DLL_Debug/ptypes21.pdb + .\DLL_Debug/ptypes21.lib + MachineX86 + + + true + .\DLL_Debug/PTypes_DLL.bsc + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\DLL_Release/PTypes_DLL.tlb + + + + + MaxSpeed + OnlyExplicitInline + ../include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;PTYPES_DLL_EXPORTS;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\DLL_Release/PTypes_DLL.pch + .\DLL_Release/ + .\DLL_Release/ + .\DLL_Release/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0419 + + + ws2_32.lib;%(AdditionalDependencies) + DLL_Release/ptypes21.dll + true + .\DLL_Release/ptypes21.pdb + true + .\DLL_Release/ptypes21.map + .\DLL_Release/ptypes21.lib + MachineX86 + + + true + .\DLL_Release/PTypes_DLL.bsc + + + mkdir ..\so\ +copy DLL_Release\ptypes21.lib ..\so\ +copy DLL_Release\ptypes21.dll ..\so\ + + + + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_DLL.vcxproj.filters --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_DLL.vcxproj.filters Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,216 @@ + + + + + {03b5f83a-8831-4a02-b142-3dea413bd4cf} + + + {00cde44f-153d-41d7-ad67-0291b6987ac0} + + + {a8c44998-3031-4332-bc12-4628471b4ef9} + + + {020aa4dd-587a-492c-99e8-a4b5bf15a2e4} + + + {de2eaf6f-0c2e-41d2-8c98-95e92ca1e71b} + + + {3248f09b-f155-47b0-be1c-ab36e64d6b44} + *.rc,*.h + + + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Async + + + Async + + + Async + + + Async + + + Async + + + Async + + + Async + + + Async + + + Async + + + Inet + + + Inet + + + Inet + + + Inet + + + Inet + + + Inet + + + + + Public Headers + + + Public Headers + + + Public Headers + + + Public Headers + + + Public Headers + + + Public Headers + + + Resources + + + + + Resources + + + + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_DLL.vcxproj.user --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_DLL.vcxproj.user Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Lib.vcproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Lib.vcproj Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,1394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Lib.vcxproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Lib.vcxproj Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,450 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {4A435BFE-D414-4FFA-8364-672A2B7FFF01} + + + + StaticLibrary + false + MultiByte + + + StaticLibrary + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + .\Release\ + .\Release\ + .\Debug\ + .\Debug\ + AllRules.ruleset + + + AllRules.ruleset + + + + + + MaxSpeed + OnlyExplicitInline + ../include;%(AdditionalIncludeDirectories) + _LIB;NDEBUG;WIN32;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\Release/PTypes_Lib.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Release\ptypes.lib + true + + + true + .\Release/PTypes_Lib.bsc + + + mkdir ..\lib\ +copy Release\ptypes.lib ..\lib\ + + + + + + Disabled + ../include;%(AdditionalIncludeDirectories) + _LIB;_DEBUG;WIN32;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + .\Debug/PTypes_Lib.pch + .\Debug/ + .\Debug/ + .\Debug/ + true + Level4 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Debug\ptypes.lib + true + + + true + .\Debug/PTypes_Lib.bsc + + + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Lib.vcxproj.filters --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Lib.vcxproj.filters Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,209 @@ + + + + + {054093b8-d1c6-4f6f-a342-c01d06cac267} + h;cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {91444797-eef9-4801-9d5d-7d0a97c25fe5} + h;hpp;hxx;hm;inl + + + {4d75cde2-1d88-4d28-8935-4c156005ee21} + h;cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {458d2fec-26f8-45e5-802a-9df3ccf9c6e5} + h;cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {c8d49101-57f3-4cca-8c34-f2078813bc90} + h;cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Async + + + Async + + + Async + + + Async + + + Async + + + Async + + + Async + + + Async + + + Async + + + Inet + + + Inet + + + Inet + + + Inet + + + Inet + + + Inet + + + + + Public Headers + + + Public Headers + + + Public Headers + + + Public Headers + + + Public Headers + + + Public Headers + + + + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Lib.vcxproj.user --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Lib.vcxproj.user Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Lib_ST.vcproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Lib_ST.vcproj Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,1191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Lib_ST.vcxproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Lib_ST.vcxproj Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,396 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {FB3CDEFD-B016-4EFE-8634-86083A584B04} + + + + StaticLibrary + false + MultiByte + + + StaticLibrary + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + .\Debug_ST\ + .\Debug_ST\ + .\Release_ST\ + .\Release_ST\ + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ../include;%(AdditionalIncludeDirectories) + _DEBUG;_LIB;WIN32;PTYPES_ST;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + .\Debug_ST/PTypes_Lib_ST.pch + .\Debug_ST/ + .\Debug_ST/ + .\Debug_ST/ + true + Level4 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Debug_ST\ptypesn.lib + true + + + true + .\Debug_ST/PTypes_Lib_ST.bsc + + + + + MaxSpeed + OnlyExplicitInline + ../include;%(AdditionalIncludeDirectories) + NDEBUG;_LIB;WIN32;PTYPES_ST;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release_ST/PTypes_Lib_ST.pch + .\Release_ST/ + .\Release_ST/ + .\Release_ST/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Release_ST\ptypesn.lib + true + + + true + .\Release_ST/PTypes_Lib_ST.bsc + + + mkdir ..\lib\ +copy Release_ST\ptypesn.lib ..\lib\ + + + + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Lib_ST.vcxproj.filters --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Lib_ST.vcxproj.filters Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,178 @@ + + + + + {9839b624-c96b-4a86-9d06-746bdf6f840e} + h;cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {7a1c620f-f7c4-421f-be15-de70f0ca2bc7} + h;hpp;hxx;hm;inl + + + {7883e225-fd60-42ea-a9c4-0e5f19e0d5b9} + h;cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {78775f48-de12-4f23-a22d-8a940ee7320e} + h;cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Types + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Streams + + + Inet + + + Inet + + + Inet + + + Inet + + + Inet + + + Inet + + + + + Public Headers + + + Public Headers + + + Public Headers + + + Public Headers + + + Public Headers + + + Public Headers + + + + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Lib_ST.vcxproj.user --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Lib_ST.vcxproj.user Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Test.vcproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Test.vcproj Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Test.vcxproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Test.vcxproj Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,152 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {A08093B3-4E89-4D19-85FD-D0679E7DC4EA} + + + + Application + false + MultiByte + + + Application + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + .\DLL_Debug\ + .\DLL_Debug\ + false + .\DLL_Release\ + .\DLL_Release\ + false + AllRules.ruleset + + + AllRules.ruleset + + + + + + .\DLL_Debug/PTypes_Test.tlb + + + + + Disabled + ../include;%(AdditionalIncludeDirectories) + _CONSOLE;_DEBUG;WIN32;PTYPES_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + .\DLL_Debug/PTypes_Test.pch + .\DLL_Debug/ + .\DLL_Debug/ + .\DLL_Debug/ + true + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;%(AdditionalDependencies) + .\DLL_Debug/PTypes_Test.exe + true + true + .\DLL_Debug/PTypes_Test.pdb + Console + MachineX86 + + + true + .\DLL_Debug/PTypes_Test.bsc + + + + + .\DLL_Release/PTypes_Test.tlb + + + + + MaxSpeed + OnlyExplicitInline + ../include;%(AdditionalIncludeDirectories) + _CONSOLE;NDEBUG;WIN32;PTYPES_DLL;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\DLL_Release/PTypes_Test.pch + .\DLL_Release/ + .\DLL_Release/ + .\DLL_Release/ + true + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;%(AdditionalDependencies) + .\DLL_Release/PTypes_Test.exe + true + .\DLL_Release/PTypes_Test.pdb + true + .\DLL_Release/PTypes_Test.map + Console + MachineX86 + + + true + .\DLL_Release/PTypes_Test.bsc + + + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + + + {181e52de-3cf7-425b-b24a-e59711635486} + false + + + + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Test.vcxproj.user --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Test.vcxproj.user Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Test_ST.vcproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Test_ST.vcproj Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Test_ST.vcxproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Test_ST.vcxproj Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,152 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {ADC21731-3254-476F-8D37-8266E1EC293D} + + + + Application + false + MultiByte + + + Application + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + .\Release_ST\ + .\Release_ST\ + false + .\Debug_ST\ + .\Debug_ST\ + false + AllRules.ruleset + + + AllRules.ruleset + + + + + + .\Release_ST/PTypes_Test_ST.tlb + + + + + MaxSpeed + OnlyExplicitInline + ../include;%(AdditionalIncludeDirectories) + _CONSOLE;NDEBUG;WIN32;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release_ST/PTypes_Test_ST.pch + .\Release_ST/ + .\Release_ST/ + .\Release_ST/ + true + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;%(AdditionalDependencies) + .\Release_ST/PTypes_Test_ST.exe + true + .\Release_ST/PTypes_Test_ST.pdb + true + .\Release_ST/PTypes_Test_ST.map + Console + MachineX86 + + + true + .\Release_ST/PTypes_Test_ST.bsc + + + + + .\Debug_ST/PTypes_Test_ST.tlb + + + + + Disabled + ../include;%(AdditionalIncludeDirectories) + _CONSOLE;_DEBUG;WIN32;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + .\Debug_ST/PTypes_Test_ST.pch + .\Debug_ST/ + .\Debug_ST/ + .\Debug_ST/ + true + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + ws2_32.lib;%(AdditionalDependencies) + .\Debug_ST/PTypes_Test_ST.exe + true + true + .\Debug_ST/PTypes_Test_ST.pdb + Console + MachineX86 + + + true + .\Debug_ST/PTypes_Test_ST.bsc + + + + + %(AdditionalIncludeDirectories) + PTYPES_ST;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + PTYPES_ST;%(PreprocessorDefinitions) + + + + + {fb3cdefd-b016-4efe-8634-86083a584b04} + false + + + + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/PTypes_Test_ST.vcxproj.user --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/PTypes_Test_ST.vcxproj.user Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/UpgradeLog.XML --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/UpgradeLog.XML Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/dll_version.rc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/dll_version.rc Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,102 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,1,1,1 + PRODUCTVERSION 2,1,1,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "http://www.melikyan.com/ptypes/" + VALUE "FileDescription", "C++ Portable Types Library (PTypes) DLL [MSVC]" + VALUE "FileVersion", "2, 1, 1, 1" + VALUE "InternalName", "ptypes" + VALUE "LegalCopyright", "Copyright © 2001-2007, Hovik Melikyan" + VALUE "OriginalFilename", "ptypes21.dll" + VALUE "ProductName", "C++ Portable Types Library (PTypes)" + VALUE "ProductVersion", "2, 1, 1, 1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/ipch/ptypes_lib-8b061a97/debug/ptypes_lib-d36c6ce4.ipch Binary file win32/ipch/ptypes_lib-8b061a97/debug/ptypes_lib-d36c6ce4.ipch has changed diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/resource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/resource.h Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by dll_version.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/wshare.vcproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/wshare.vcproj Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,527 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/wshare.vcxproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/wshare.vcxproj Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,237 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {6B53FB0A-5052-4A7B-8419-7CBF117088EB} + + + + Application + false + MultiByte + + + Application + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + .\Debug\ + .\Debug\ + false + .\Release\ + .\Release\ + false + AllRules.ruleset + + + AllRules.ruleset + + + + + + .\Debug/wshare.tlb + + + + + Disabled + ../include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + .\Debug/wshare.pch + .\Debug/ + .\Debug/ + .\Debug/ + true + Level4 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0419 + + + Ws2_32.lib;Advapi32.lib;%(AdditionalDependencies) + .\Debug/wshare.exe + true + true + .\Debug/wshare.pdb + Console + MachineX86 + + + true + .\Debug/wshare.bsc + + + + + .\Release/wshare.tlb + + + + + MaxSpeed + OnlyExplicitInline + ../include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\Release/wshare.pch + .\Release/ + .\Release/ + .\Release/ + true + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0419 + + + Ws2_32.lib;Advapi32.lib;%(AdditionalDependencies) + .\Release/wshare.exe + true + .\Release/wshare.pdb + Console + MachineX86 + + + true + .\Release/wshare.bsc + + + mkdir ..\bin\ +copy Release\wshare.exe ..\bin\ + + + + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + + + + + + + + + + + + + {4a435bfe-d414-4ffa-8364-672a2b7fff01} + false + + + + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 win32/wshare.vcxproj.user --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/wshare.vcxproj.user Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/Makefile.Darwin --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/Makefile.Darwin Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,20 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for MacOS X (Darwin), called from ../Makefile +# + +CXX = c++ + +OS_CXXOPTS = -Wall + +include Makefile.common + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/Makefile.FreeBSD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/Makefile.FreeBSD Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,21 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for FreeBSD, called from ../Makefile +# + +CXX = g++ + +OS_CXXOPTS = -Wall -pthread +# OS_LDLIBS = -lc_r + +include Makefile.common + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/Makefile.HP-UX --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/Makefile.HP-UX Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,21 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for HP-UX, called from ../Makefile +# + +CXX = aCC + +OS_CXXOPTS = -z -ext -mt +z -D_HPUX_SOURCE -D_FILE_OFFSET_BITS=64 +OS_LDLIBS = -lrt + +include Makefile.common + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/Makefile.Linux --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/Makefile.Linux Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,20 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for Linux, called from ../Makefile +# + +CXX = g++ + +OS_CXXOPTS = -Wall -pthread -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 + +include Makefile.common + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/Makefile.SunOS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/Makefile.SunOS Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,21 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for SunOS, called from ../Makefile +# + +CXX = g++ + +OS_CXXOPTS = -Wall -D_REENTRANT -D_FILE_OFFSET_BITS=64 +OS_LDLIBS = -lpthread -lsocket -lnsl -lrt + +include Makefile.common + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/Makefile.common --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/Makefile.common Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,77 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# +# +# Makefile for all platforms, called automatically from +# Makefile. +# + +.SUFFIXES: .cxx .o + +DDEBUG = -DDEBUG +INCDIR = ../include +CXXOPTS = $(OS_CXXOPTS) $(DDEBUG) -I$(INCDIR) -O2 +LDLIBS = $(OS_LDLIBS) + +BINDEST = ../bin + +OBJS = wshare.o request.o clients.o sysutils.o urlutils.o log.o \ + mimetable.o config.o utils.o modules.o \ + mod_file.o mod_wstat.o mod_about.o + + +.cxx.o: + $(CXX) -c $(CXXOPTS) $< + + +all: wshare$(OS_BINEXT) + + +wshare$(OS_BINEXT): $(OBJS) ../lib/libptypes.a + $(CXX) $(CXXOPTS) $(OBJS) ../lib/libptypes.a $(LDLIBS) -o $@ + mkdir -p $(BINDEST) ; cp $@ $(BINDEST)/ + strip $(BINDEST)/$@ + + +wshare.o: wshare.cxx clients.h request.h sysutils.h urlutils.h log.h config.h + +request.o: request.cxx request.h modules.h clients.h sysutils.h urlutils.h log.h config.h + +clients.o: clients.cxx clients.h log.h config.h + +sysutils.o: sysutils.cxx sysutils.h utils.h + +urlutils.o: urlutils.cxx urlutils.h + +utils.o: utils.cxx utils.h sysutils.h urlutils.h config.h + +log.o: log.cxx log.h config.h + +config.o: config.cxx config.h sysutils.h + +mimetable.o: mimetable.cxx config.h + +modules.o: modules.cxx modules.h request.h + +mod_file.o: mod_file.cxx config.h sysutils.h utils.h request.h clients.h + +mod_wstat.o: mod_wstat.cxx config.h utils.h request.h clients.h + +mod_about.o: mod_about.cxx config.h utils.h request.h + + +clean: clean-src + rm -f $(BINDEST)/wshare$(OS_BINEXT) + +clean-src: + rm -f *.o + rm -f core *.core + rm -f wshare$(OS_BINEXT) + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/clients.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/clients.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,126 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include + +#include "config.h" +#include "log.h" +#include "clients.h" + + +USING_PTYPES + + +thread_list threads; +int thread_count; +int thread_seq; +datetime started; + + +thread_list::thread_list(): lock(), count(0), list(0) +{ +} + + +thread_list::~thread_list() +{ + memfree(list); +} + + +void thread_list::set_capacity(int icount) +{ + if (list != 0) + fatal(1001, ""); + count = icount; + list = (client_thread**)memalloc(sizeof(client_thread*) * count); + memset(list, 0, sizeof(client_thread*) * count); +} + + +void thread_list::add(client_thread* t) +{ + scopewrite _lock(lock); + int i; + for (i = 0; i < count; i++) + if (list[i] == 0) + break; + if (i == count) + fatal(1002, ""); + list[i] = t; +} + + +void thread_list::del(client_thread* t) +{ + scopewrite _lock(lock); + int i; + for (i = 0; i < count; i++) + if (list[i] == t) + break; + if (i == count) + fatal(1003, ""); + list[i] = 0; +} + + +client_thread::client_thread(ipstream* iclient) + : thread(true), + request_rec(*iclient, *iclient, iclient->get_ip()), + client(iclient), seq_num(0) +{ + pincrement(&thread_count); +} + + +void client_thread::cleanup() +{ + delete client; + threads.del(this); +} + + +client_thread::~client_thread() +{ + pdecrement(&thread_count); +} + + +void client_thread::execute() +{ + seq_num = pincrement(&thread_seq); + threads.add(this); + + try + { + while (1) + { + request_rec::respond(); + if (!client->get_active()) + break; + if (!client->waitfor(DEF_KEEP_ALIVE_TIMEOUT)) + break; + if (client->get_eof()) + break; + reset_state(); + } + } + catch(estream* e) + { + htlog_write(client_ip, req_line, rsp_code, sockout->tellx() - hdr_size, referer); + client->close(); + delete e; + } + + client->close(); +} + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/clients.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/clients.h Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,66 @@ +/* + * + * 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 W_CLIENTS_H +#define W_CLIENTS_H + + +#include +#include + +#include "request.h" + + +USING_PTYPES + + +class client_thread; + + +class thread_list +{ +public: + rwlock lock; + int count; + client_thread** list; + + thread_list(); + virtual ~thread_list(); + void set_capacity(int icount); + void add(client_thread* t); + void del(client_thread* t); +}; + + +class client_thread: public thread, public request_rec +{ +protected: + ipstream* client; + int seq_num; // sequential number, pseudo-id + virtual void execute(); + virtual void cleanup(); +public: + + client_thread(ipstream* iclient); + virtual ~client_thread(); + + int get_seq_num() { return seq_num; } +}; + + +extern thread_list threads; +extern int thread_count; +extern int thread_seq; +extern datetime started; + + +#endif diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/config.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/config.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,167 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include +#include + +#include "ptypes.h" + +#include "config.h" + + +USING_PTYPES + + +const char* SERVER_APP_NAME = "wshare/1.3" +#ifdef WIN32 + " (Win32)"; +#else + " (UNIX)"; +#endif + +const char* DEF_MIME_TYPE = "text/plain"; // no extension +const char* DEF_BINARY_TYPE = "application/octet-stream"; // for unix binaries with no extension + + +const char* STD_CSS = + "\n"; + + +const char* cfg_index_files[] = +{ + "index.html", + "Index.html", + "default.htm", + // add your default index files here + NULL // terminator +}; + + +// configurable parameters + +string cfg_server_name; +string cfg_document_root; +int cfg_port = DEF_HTTP_PORT; +bool cfg_syslog = true; +bool cfg_dir_indexes = false; +bool cfg_def_index_files = true; +bool cfg_log_referer = true; +bool cfg_file_mtime = true; +bool cfg_daemonize = false; +string cfg_user; +string cfg_group; +string cfg_log_file; +int cfg_max_clients = DEF_MAX_CLIENTS; +int cfg_max_keep_alive = (DEF_MAX_CLIENTS * 2) / 3; + +char* myname = "wshare"; + + +static void usage() +{ + static const char* usage_str = +"%s, a simple HTTP daemon.\n\n" +"usage: %s [options] document-root\n\n" +" -D daemonize, UNIX only\n" +" -d allow directory indexes\n" +" -g group group ID to run as, UNIX only\n" +" -n num maximum number of simultaneous connections (default: %d)\n" +" -o file-name write HTTP access log to file-name\n" +" -p port-num port number to listen to\n" +" -u user user ID to run as, UNIX only\n" +" -x always show directory indexes (ignore default index files)\n" +"\n"; + + printf(usage_str, pconst(SERVER_APP_NAME), myname, DEF_MAX_CLIENTS); + exit(255); +} + + +static int arg_count; +static char** args; +static char* arg_ptr; +static int arg_num; + + +static char* arg_param() +{ + arg_ptr++; + if (*arg_ptr == 0) + { + if (++arg_num >= arg_count) + usage(); + arg_ptr = args[arg_num]; + } + char* res = arg_ptr; + arg_ptr += strlen(res); + return res; +} + + +void config_init(int argc, char* argv[]) +{ + arg_count = argc; + args = argv; + + if (arg_count == 1) + usage(); + + arg_num = 1; + while (arg_num < arg_count) + { + arg_ptr = args[arg_num]; + if (*arg_ptr != '-') + { + cfg_document_root = arg_ptr; + arg_num++; + continue; + } + + arg_ptr++; + +opt2: + switch(*arg_ptr) + { + case 'D': cfg_daemonize = true; arg_ptr++; break; + case 'd': cfg_dir_indexes = true; arg_ptr++; break; + case 'n': + cfg_max_clients = atoi(arg_param()); + cfg_max_keep_alive = (cfg_max_clients * 2) / 3; + break; + case 'o': cfg_log_file = arg_param(); break; + case 'p': cfg_port = atoi(arg_param()); break; + case 'x': cfg_def_index_files = false; cfg_dir_indexes = true; arg_ptr++; break; + case 'u': cfg_user = arg_param(); break; + case 'g': cfg_group = arg_param(); break; + default: usage(); break; + } + + if (*arg_ptr != 0) + goto opt2; + + arg_num++; + } + + if (isempty(cfg_document_root)) + usage(); +} + + +void config_done() +{ +} + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/config.h Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,81 @@ +/* + * + * 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 W_CONFIG_H +#define W_CONFIG_H + + +#include + + +USING_PTYPES + + +// things that can hardly change + +#define MAX_TOKEN 4096 +#define MAX_REQUEST_URI 4096 +#define FILE_BUF_SIZE 4096 +#define SOCKET_BUF_SIZE 2048 +#define DEF_HTTP_PORT 80 +#define DEF_KEEP_ALIVE_TIMEOUT 15000 +#define DEF_MAX_CLIENTS 30 + + +// we no longer use strftime for HTTP time stamps, since it may +// depend on the system locale. now we build the time stamp +// `manually' instead +// #define HTTP_DATE_FMT "%a, %d %b %Y %H:%M:%S GMT" + + +// built-in configuration + +extern const char* SERVER_APP_NAME; // "wshare/1.2 (system)" +extern const char* DEF_MIME_TYPE; // "text/plain" for files with no extension +// not implemented: extern const char* DEF_BINARY_TYPE; // "application/octet-stream" for unix binaries +extern const char* STD_CSS; // CSS for built-in responses, such like 404 Not found + +extern const char* cfg_index_files[]; // index.html, Index.html and default.htm +extern const char* mimetypes[]; // built-in MIME types and extensions (in mimetable.cxx) + + +// configurable parameters + +extern string cfg_document_root; // no default, must be specified through cmdline +extern string cfg_server_name; // default is my nodename +extern int cfg_port; // 80 +extern bool cfg_dir_indexes; // allow directory indexes +extern bool cfg_def_index_files; // use default index files index.html, ... +extern string cfg_log_file; // access log file name +extern bool cfg_log_referer; // include referer in log +extern bool cfg_file_mtime; // send `last-modified' for html files +extern int cfg_max_clients; // max number of simultaneous connections, default 30 +extern int cfg_max_keep_alive; // max keep-alive clients, currently 2/3 of max_clients + +extern bool cfg_syslog; // write the log to stderr or to Unix syslog +extern string cfg_user; // user name to run as on Unix +extern string cfg_group; // group name to run as on Unix +extern bool cfg_daemonize; // daemonize on Unix + +extern char* myname; // "wshare", for syslog + + +void config_init(int argc, char* argv[]); +void config_done(); + + +#ifdef _MSC_VER +// we don't want "conditional expression is constant" warning +# pragma warning (disable: 4127) +#endif + + +#endif diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/log.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/log.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,126 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + + +#include +#include + +#ifndef WIN32 +# include +#endif + +#include +#include + +#include "config.h" +#include "log.h" + + +USING_PTYPES + + +compref htlog; +compref errlog; + + +#ifdef WIN32 +# define vsnprintf _vsnprintf +#endif + + +void log_init() +{ + htlog = &perr; + errlog = &perr; +#ifndef WIN32 + if (cfg_syslog) + openlog(myname, 0, LOG_USER); +#endif +} + + +void log_done() +{ +#ifndef WIN32 + if (cfg_syslog) + closelog(); +#endif +} + + +void syslog_write(log_severity_t pri, const char* fmt, ...) +{ + char buf[2048]; + va_list va; + va_start(va, fmt); + + vsnprintf(buf, sizeof(buf), fmt, va); + +#ifndef WIN32 + if (cfg_syslog) + { + // syslog is available only on Unix + static int upri[4] = {LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_INFO}; + syslog(upri[pri], "%s", buf); + } +#endif + + if (errlog != 0) + { + static pconst spri[4] = {"FATAL: ", "Error: ", "", ""}; + errlog->putf("%s: %t %s%s\n", myname, now(), spri[pri], buf); + errlog->flush(); + } + + va_end(va); +} + + +void htlog_write(ipaddress ip, string request, int code, large size, string referer) +{ + if (htlog == 0) + return; + + if (isempty(referer)) + referer = '-'; + int t = tzoffset(); + bool neg = t < 0; + if (neg) + t = -t; + string ssize; + if (size < 0) + ssize = '-'; + else + ssize = itostring(size); + + string sdate = nowstring("%d/%b/%Y:%H:%M:%S", false); + + if (cfg_log_referer) + referer = " \"" + referer + '\"'; + else + clear(referer); + + try + { + htlog->putf("%a - - [%s %c%02d%02d] \"%s\" %d %s%s\n", + long(ip), pconst(sdate), neg ? '-' : '+', t / 60, t % 60, + pconst(request), code, pconst(ssize), pconst(referer)); + htlog->flush(); + } + catch (estream* e) + { + delete e; + htlog = 0; + syslog_write(SYSLOG_ERROR, "HTTP log disabled due to failed write attempt (daemonized?)"); + } +} + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/log.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/log.h Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,36 @@ +/* + * + * 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 W_LOG_H +#define W_LOG_H + + +#include +#include + + +USING_PTYPES + + +enum log_severity_t {SYSLOG_FATAL, SYSLOG_ERROR, SYSLOG_WARNING, SYSLOG_INFO}; + + +extern compref htlog; // perr by default +extern compref errlog; // perr, until daemonized + + +void log_init(); +void log_done(); +void syslog_write(log_severity_t pri, const char* fmt, ...); +void htlog_write(ipaddress ip, string request, int code, large size, string referer); + + +#endif diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/mimetable.awk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/mimetable.awk Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,32 @@ +# +# +# C++ Portable Types Library (PTypes) +# Version 2.1.1 Released 27-Jun-2007 +# +# Copyright (C) 2001-2007 Hovik Melikyan +# +# http://www.melikyan.com/ptypes/ +# +# + +# +# Convert Apache's mime.types file to C++ declaration +# + +BEGIN { + printf "//\n// Generated from Apache's mime.types file by mimetypes.awk\n//\n\n\ +const char* mimetypes[] = {\n"; +} + +NF > 1 && substr($0, 0, 1) != "#" { + printf " "; + for (i = 2; i <= NF; i++) + printf "\".%s\", ", $i; + printf "\"%s\",\n", $1; +} + + +END { + printf " 0,\n};\n"; +} + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/mimetable.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/mimetable.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,116 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ +// +// Generated from Apache's mime.types file by mimetypes.awk +// + +// note that the order was changed later to bring +// more frequently used extensions to the top + +const char* mimetypes[] = { + ".html", ".htm", "text/html", + ".css", "text/css", + ".gif", "image/gif", + ".jpeg", ".jpg", ".jpe", "image/jpeg", + ".png", "image/png", + ".js", "application/x-javascript", + ".mpga", ".mp2", ".mp3", "audio/mpeg", + ".mid", ".midi", ".kar", "audio/midi", + ".mpeg", ".mpg", ".mpe", "video/mpeg", + ".avi", "video/x-msvideo", + ".zip", "application/zip", + ".hqx", "application/mac-binhex40", + ".xml", ".xsl", "text/xml", + ".swf", "application/x-shockwave-flash", + ".bin", ".dms", ".lha", ".lzh", ".exe", ".class", ".so", ".dll", "application/octet-stream", + ".pdf", "application/pdf", + ".asc", ".txt", "text/plain", + ".doc", "application/msword", + ".rtf", "text/rtf", + ".ai", ".eps", ".ps", "application/postscript", + + ".ez", "application/andrew-inset", + ".cpt", "application/mac-compactpro", + ".oda", "application/oda", + ".smi", ".smil", "application/smil", + ".mif", "application/vnd.mif", + ".xls", "application/vnd.ms-excel", + ".ppt", "application/vnd.ms-powerpoint", + ".wbxml", "application/vnd.wap.wbxml", + ".wmlc", "application/vnd.wap.wmlc", + ".wmlsc", "application/vnd.wap.wmlscriptc", + ".bcpio", "application/x-bcpio", + ".vcd", "application/x-cdlink", + ".pgn", "application/x-chess-pgn", + ".cpio", "application/x-cpio", + ".csh", "application/x-csh", + ".dcr", ".dir", ".dxr", "application/x-director", + ".dvi", "application/x-dvi", + ".spl", "application/x-futuresplash", + ".gtar", "application/x-gtar", + ".hdf", "application/x-hdf", + ".skp", ".skd", ".skt", ".skm", "application/x-koan", + ".latex", "application/x-latex", + ".nc", ".cdf", "application/x-netcdf", + ".sh", "application/x-sh", + ".shar", "application/x-shar", + ".sit", "application/x-stuffit", + ".sv4cpio", "application/x-sv4cpio", + ".sv4crc", "application/x-sv4crc", + ".tar", "application/x-tar", + ".tcl", "application/x-tcl", + ".tex", "application/x-tex", + ".texinfo", ".texi", "application/x-texinfo", + ".t", ".tr", ".roff", "application/x-troff", + ".man", "application/x-troff-man", + ".me", "application/x-troff-me", + ".ms", "application/x-troff-ms", + ".ustar", "application/x-ustar", + ".src", "application/x-wais-source", + ".xhtml", ".xht", "application/xhtml+xml", + ".au", ".snd", "audio/basic", + ".aif", ".aiff", ".aifc", "audio/x-aiff", + ".m3u", "audio/x-mpegurl", + ".ram", ".rm", "audio/x-pn-realaudio", + ".rpm", "audio/x-pn-realaudio-plugin", + ".ra", "audio/x-realaudio", + ".wav", "audio/x-wav", + ".pdb", "chemical/x-pdb", + ".xyz", "chemical/x-xyz", + ".bmp", "image/bmp", + ".ief", "image/ief", + ".tiff", ".tif", "image/tiff", + ".djvu", ".djv", "image/vnd.djvu", + ".wbmp", "image/vnd.wap.wbmp", + ".ras", "image/x-cmu-raster", + ".pnm", "image/x-portable-anymap", + ".pbm", "image/x-portable-bitmap", + ".pgm", "image/x-portable-graymap", + ".ppm", "image/x-portable-pixmap", + ".rgb", "image/x-rgb", + ".xbm", "image/x-xbitmap", + ".xpm", "image/x-xpixmap", + ".xwd", "image/x-xwindowdump", + ".igs", ".iges", "model/iges", + ".msh", ".mesh", ".silo", "model/mesh", + ".wrl", ".vrml", "model/vrml", + ".rtx", "text/richtext", + ".sgml", ".sgm", "text/sgml", + ".tsv", "text/tab-separated-values", + ".wml", "text/vnd.wap.wml", + ".wmls", "text/vnd.wap.wmlscript", + ".etx", "text/x-setext", + ".qt", ".mov", "video/quicktime", + ".mxu", "video/vnd.mpegurl", + ".movie", "video/x-sgi-movie", + ".ice", "x-conference/x-cooltalk", + 0, +}; diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/mod_about.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/mod_about.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,50 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "config.h" +#include "utils.h" +#include "request.h" + + +// +// a sample path handler that responds to http://hostname/.about +// see modules.h and request.h for details +// + +void handle_about(request_rec& req) +{ + req.keep_alive = false; // we don't know the content length + + // all responses must start with begin_response() and end with end_response() + req.begin_response(200, "OK"); + + // use put_xxx functions (see request.h) to send response headers back to the + // client. these functions do nothing if the request version was HTTP/0.9 + req.put_content_type("text/html"); + + // end_headers() must be called when you're done with the headers. + // if the method was HEAD, it throws an ehttp exception so that the + // rest of your code won't be executed + req.end_headers(); + + std_html_header(*req.sockout, "about wshare"); + + // you can write to the client socket using req.sockout, which is an outstm object + req.sockout->putf("

%s
\n" + "PTypes (C++ Portable Types Library)\n" + "demo program
\n" + "written by Hovik Melikyan

\n", SERVER_APP_NAME); + + std_html_footer(*req.sockout); + + // end_response() throws an ehttp exception. the request info is being logged. + req.end_response(); +} diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/mod_file.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/mod_file.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,269 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +// +// file handling module; registered as a path handler for '/' +// + +#include + +#include "config.h" +#include "modules.h" +#include "request.h" +#include "utils.h" + + +class file_req: public file_request_rec +{ +protected: + request_rec* req; + + void analyze_uri(); + void rsp_dir_index(); + void rsp_file(); + +public: + file_req(request_rec* req); + ~file_req(); + + void respond(); +}; + + +file_req::file_req(request_rec* ireq): file_request_rec(), req(ireq) +{ +} + + +file_req::~file_req() +{ +} + + +void file_req::analyze_uri() +{ + abs_path = cfg_document_root + '/'; + rel_path = '/'; + file_type = FT_DIRECTORY; + + // analyze path components one by one and stop where the + // component does not exist, or where we see a file, not a + // directory. note, that the request-uri may be longer and + // may contain extra components which are ignored. f.ex. + // the request uri is /dir/file.html/other/stuff/. the + // scan stops at file.html and ignores the rest. this is the + // way apache and most other daemons work. + // besides, we may pass a non-existent path to a registered + // path handler. + + for (int p = 0; p < req->path_parts.get_count(); ++p) + { + string s = req->path_parts.getkey(p); + abs_path += s; + rel_path += s; + + file_type = get_file_type(abs_path); + if (file_type == FT_DIRECTORY) + { + abs_path += '/'; + rel_path += '/'; + } + else if (file_type == FT_FILE) + { + file_name = s; + break; + } + else if (file_type == FT_OTHER) // pipe or device + req->rsp_forbidden(); + else + req->rsp_not_found(); + } + + if (file_type == FT_DIRECTORY) + { + // check for the trailing slash and redirect to the canonical + // form if necessary + if (trail_char(req->url.path) != '/') + { + req->url.path += '/'; + req->rsp_redirect(urlcreate(req->url)); + } + + // find the default index file + if (cfg_def_index_files) + { + const char** idx = cfg_index_files; + while (*idx != nil) + { + string t = abs_path + *idx; + if (is_file(t)) + { + abs_path = t; + file_type = FT_FILE; + file_name = *idx; + break; + } + idx++; + } + } + } + + // other useful info about the object + sym_link = is_symlink(abs_path); + executable = is_executable(abs_path); + if (!isempty(file_name)) + { + file_ext = get_file_ext(file_name); + handler_info* h = find_file_handler(file_ext); + if (h != 0) + { + file_callback(h->callback)(*req, *this); + // the handler must throw an ehttp exception + fatal(251, "Internal error 251"); + } + } +} + + +void file_req::rsp_dir_index() +{ + if (!cfg_dir_indexes) + req->rsp_dir_index_forbidden(); + + filist list(SL_SORTED | SL_CASESENS | SL_OWNOBJECTS); + get_directory(list, abs_path, true, 500); + if (list.get_count() == 0) + req->rsp_forbidden(); + + // we don't know the length of the resulting file + req->keep_alive = false; + + req->begin_response(200, "OK"); + req->put_content_type("text/html"); + req->end_headers(); + + // build an index HTML page + std_html_header(*req->sockout, "Index of " + rel_path); + req->sockout->put("
\n"); + req->sockout->put("
\n");
+    html_show_file_list(*req->sockout, list);
+    list.clear();
+    get_directory(list, abs_path, false, 500);
+    html_show_file_list(*req->sockout, list);
+
+    req->sockout->put("
\n"); + std_html_footer(*req->sockout); + + req->end_response(); +} + + +void file_req::rsp_file() +{ + // .ht* files are forbidden, like with Apache + if (strncmp(file_name, ".ht", 3) == 0) + req->rsp_forbidden(); + + large fsize64 = get_file_size(abs_path); + if (fsize64 < 0) + req->rsp_not_found(); + + // test the file for readability + infile f(abs_path); + try + { + f.set_bufsize(0); + f.open(); + } + catch(estream* e) + { + delete e; + req->rsp_forbidden(); + } + + // partial content + large txsize = fsize64; + if (req->partial) + { + if (req->range_max == -1) + req->range_max = fsize64 - 1; + if (req->range_min >= 0 && req->range_min < req->range_max && req->range_max < fsize64) + txsize = req->range_max - req->range_min + 1; + else + req->partial = false; + } + + // send headers + datetime fmtime = get_file_mtime(abs_path); + if (req->if_modified != invdatetime && fmtime != invdatetime && fmtime <= req->if_modified) + req->rsp_not_modified(); + + if (req->partial) + req->begin_response(206, "Partial Content"); + else + req->begin_response(200, "OK"); + req->put_content_type(get_mimetype(abs_path)); + req->put_content_length(txsize); + if (req->partial) + req->put_header("Content-Range", + "bytes " + itostring(req->range_min) + '-' + itostring(req->range_max) + '/' + itostring(fsize64)); + if (cfg_file_mtime) + req->put_header("Last-Modified", http_time_stamp(fmtime)); + req->end_headers(); + + // send content + if (req->partial) + f.seekx(req->range_min); + char buf[FILE_BUF_SIZE]; + while (txsize > 0) + { + int toread = sizeof(buf); + if (toread > txsize) + toread = (int)txsize; + int r = f.read(buf, toread); + if (r <= 0) + break; + req->sockout->write(buf, r); + txsize -= r; + } + + // if for some reason the number of bytes sent does not correspond to the + // promised content length, just close the connection + if (txsize != 0) + req->keep_alive = false; + + req->end_response(); +} + + +void file_req::respond() +{ + if (req->method != HTTP_GET && req->method != HTTP_HEAD) + req->rsp_bad_method("GET, HEAD"); + + analyze_uri(); + + if (file_type == FT_DIRECTORY) + rsp_dir_index(); + + else if (file_type == FT_FILE) + rsp_file(); + + else + req->rsp_not_found(); +} + + +void handle_file(request_rec& req) +{ + file_req freq(&req); + freq.respond(); +} diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/mod_wstat.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/mod_wstat.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,93 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "config.h" +#include "utils.h" +#include "request.h" +#include "clients.h" + + +const char* stat_str[STAT_MAX] = {"READ ", "WRITE ", "WAIT "}; + + +static ipaddress localhost(127, 0, 0, 1); + + +static void show_lifetime(outstm* sockout, datetime t) +{ + datetime diff = now() - t; + int d = days(diff); + if (d > 0) + sockout->putf("%dd ", d); + sockout->put(dttostring(diff, "%H:%M:%S")); +} + + +void handle_wstat(request_rec& req) +{ + // only requests from localhost are allowed + if (req.client_ip != localhost) + req.rsp_forbidden(); + + req.keep_alive = false; + + req.begin_response(200, "OK"); + req.put_content_type("text/html"); + req.end_headers(); + + std_html_header(*req.sockout, "wshare status report"); + req.sockout->put("
\n");
+    req.sockout->putf("  Requests: %d\n", thread_seq);
+    req.sockout->put("  Running: ");
+    show_lifetime(req.sockout, ::started);
+    req.sockout->put("\n\n");
+    req.sockout->put("  Client          Status Lifetime  Request\n");
+    req.sockout->put("
\n"); + + for (int i = 0; i < threads.count; i++) + { + if (threads.list[i] == 0) + continue; + + // copy all parameters to local vars to free the thread_list mutex earlier + ipaddress tclient_ip = 0; + req_stat_t tstat = STAT_READ; + datetime tstarted = invdatetime; + string treq_line; + { + scoperead _lock(threads.lock); + + client_thread* t = threads.list[i]; + if (t != 0) + { + tclient_ip = t->client_ip; + tstat = t->stat; + tstarted = t->started; + treq_line = t->req_line; + } + } + + if (tclient_ip == 0) + continue; + + req.sockout->putf(" %-15s %s", pconst(iptostring(tclient_ip)), stat_str[tstat]); + show_lifetime(req.sockout, tstarted); + req.sockout->put(" "); + html_encode(*req.sockout, treq_line); + + req.sockout->put("\n"); + } + + req.sockout->put("
\n"); + std_html_footer(*req.sockout); + + req.end_response(); +} diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/modules.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/modules.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,85 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include "request.h" +#include "modules.h" + + +USING_PTYPES + + +static handler_info* method_list; +static handler_info* path_list; +static handler_info* file_list; + + +handler_info::handler_info(handler_info* inext, void* icallback, const string& iparam) + : next(inext), callback(icallback), param(iparam) +{ +} + + +void add_method_handler(const string& method, method_callback cb) +{ + method_list = new handler_info(method_list, (void*)cb, method); +} + + +void add_path_handler(const string& path, path_callback cb) +{ + path_list = new handler_info(path_list, (void*)cb, path); +} + + + +void add_file_handler(const string& ext, file_callback cb) +{ + file_list = new handler_info(file_list, (void*)cb, ext); +} + + +handler_info* find_handler(handler_info* list, const string& param) +{ + while (list != 0) + { + if (list->param == param) + return list; + list = list->next; + } + return 0; +} + + +handler_info* find_method_handler(const string& method) +{ + return find_handler(method_list, method); +} + + +handler_info* find_path_handler(const string& path) +{ + return find_handler(path_list, path); +} + + +handler_info* find_file_handler(const string& ext) +{ + return find_handler(file_list, ext); +} + + +void init_handlers() +{ + ADD_PATH_HANDLER("/", handle_file); + ADD_PATH_HANDLER("/.about", handle_about); + ADD_PATH_HANDLER("/.wstat", handle_wstat); +} + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/modules.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/modules.h Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,119 @@ +/* + * + * 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 W_MODULES_H +#define W_MODULES_H + + +#include + +#include "request.h" + + +USING_PTYPES + + +// +// wshare modules API +// + +// we currently only support statically linked handlers. all handlers +// receive request_rec& as a parameter and must respond by either +// calling one of the request_rec::rsp_XXX standard functions, or by +// performing some actions and giving the ehttp exception with the HTTP +// response code as a parameter. all public methods and fields of +// request_rec are at your disposal. all rsp_XXX methods throw exceptions +// of type ehttp, so they never return to the caller. + +// the following macros must be placed in init_handlers() (modules.cxx) +// for each new handler. the handler callback must exist somewhere and +// must be linked to wshare. these macros declare your callback functions +// as extern's, so you don't need to do it elsewhere. + +// there are three types of handlers: + +// method handlers are called whenever an unknown HTTP method is found +// in the request line. the rest of input data must be processed by this +// handler. you can call request_rec::parse_XXX if the request is +// HTTP/1.1-like. default methods can be overridden. + +#define ADD_METHOD_HANDLER(method,callback) \ + extern void callback(request_rec&); \ + add_method_handler(method, callback); + + +// path handlers are called when the request-URI matches the path for a +// registered handler. the request-URI path is checked one path_part at +// a time against the paths given here. the longest match wins: +// ex.: consider the uri path "/stuff/things/widget" matched against +// this handler list: +// "/" --> matches, but not the longest +// "/stuff" --> matches, but not the longest +// "/stuff/things" --> matches, the longest match +// "/stuff/things/gizmo --> doesn't match +// "/stuff/thin" --> doesn't match (partial parts are not matched) +// all request_rec fields up to `parts_used' inclusive contain valid values +// which can be used by this handler. It is also up to the handler to check +// that it can deal with the requested method (GET/HEAD/POST) +// the path parameter must contain the leading slash, and must not +// contain the trailing slash. + +#define ADD_PATH_HANDLER(path,callback) \ + extern void callback(request_rec&); \ + add_path_handler(path, callback); + + +// file handlers are called for specific file extensions for +// existing files. the ext paramter is the extension this handler +// wishes to handle. the ext parameter must contain the leading dot. + +#define ADD_FILE_HANDLER(ext,callback) \ + extern void callback(request_rec&); \ + add_file_handler(ext, callback); + + +// all handler functions must be of the following types (depending on the +// handler type): + +typedef void (*method_callback)(request_rec& req); +typedef void (*path_callback)(request_rec& req); +typedef void (*file_callback)(request_rec& req, file_request_rec& freq); + + +// +// internal module management +// + + +struct handler_info +{ + handler_info* next; + void* callback; + string param; + + handler_info(handler_info*, void*, const string&); +}; + + +handler_info* find_method_handler(const string& method); +handler_info* find_path_handler(const string& path); +handler_info* find_file_handler(const string& ext); + + +void init_handlers(); + + +void add_method_handler(const string& method, method_callback); +void add_path_handler(const string& path, path_callback); +void add_file_handler(const string& ext, file_callback); + + +#endif diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/request.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/request.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,552 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include +#include +#include + +#include "config.h" +#include "log.h" +#include "utils.h" +#include "sysutils.h" +#include "request.h" +#include "clients.h" +#include "modules.h" + + +USING_PTYPES + + +const char* http_version_str[HTTP_VER_MAX] = {"", "HTTP/1.0", "HTTP/1.1", "HTTP/1.1"}; +// const char* http_method_str[HTTP_METHOD_MAX] = {"GET", "HEAD", ""}; + + +request_rec::request_rec(instm& isockin, outstm& isockout, ipaddress iclient_ip) + : started(now()), rsp_code(0), stat(STAT_READ), sockin(&isockin), sockout(&isockout), client_ip(iclient_ip), + version(HTTP_VER_10), method(HTTP_GET), method_str(), keep_alive(false), if_modified(invdatetime), + req_line(), uri(), host(), referer(), partial(false), range_min(0), range_max(0), headers(), + url(), path_parts(), user(0), + location(), hdr_size(0) +{ +} + + +void request_rec::reset_state() +{ + rsp_code = 0; + version = HTTP_VER_10; + method = HTTP_GET; + clear(method_str); + keep_alive = false; + if_modified = invdatetime; + clear(req_line); + clear(uri); + path_parts.clear(); + clear(host); + clear(referer); + partial = false; + range_min = 0; + range_max = 0; + headers.clear(); + urlclear(url); + delete user; + user = 0; + clear(location); + hdr_size = 0; +} + + +request_rec::~request_rec() +{ + delete user; +} + + +void request_rec::put_header(const char* name, const char* value) +{ + if (version > HTTP_VER_09) + { + sockout->put(name); + sockout->put(": "); + sockout->put(value); + sockout->put("\r\n"); + } +} + + +void request_rec::put_header(const char* name, const string& value) +{ + if (version > HTTP_VER_09) + { + sockout->put(name); + sockout->put(": "); + sockout->put(value); + sockout->put("\r\n"); + } +} + + +void request_rec::put_content_type(const char* mime) +{ + put_header("Content-Type", mime); +} + + +void request_rec::put_content_length(large length) +{ + if (method != HTTP_HEAD) + put_header("Content-Length", itostring(length)); +} + + +void request_rec::end_headers() +{ + if (version > HTTP_VER_09) + sockout->put("\r\n"); + hdr_size = sockout->tell(); + if (method == HTTP_HEAD) + end_response(); +} + + +void request_rec::begin_response(int code, const char* msg) +{ + rsp_code = code; + stat = STAT_WRITE; + + if (version > HTTP_VER_09) + { + sockout->putf("%s %d %s\r\n", http_version_str[version], code, msg); + put_header("Date", http_time_stamp(now(true))); + put_header("Server", SERVER_APP_NAME); + // put_header("Accept-Ranges", "bytes"); + + if (!isempty(location)) + put_header("Location", location); + + static const char* sconn[2] = {"close", "keep-alive"}; + if (version < HTTP_VER_11) + put_header("Connection", sconn[keep_alive]); + else if (!keep_alive) // HTTP/1.1 + put_header("Connection", "close"); + } +} + + +void request_rec::std_response(bool conn_close, int code, const char* msg, const char* descr) +{ + if (conn_close) + keep_alive = false; + + // we need a memory stream to temporarily store the response + outmemory s(4096); + string smsg = msg; + + // write out the standard response page in HTML format + // to the memory stream + s.open(); + if (strlen(descr) != 0) + { + std_html_header(s, itostring(code) + ' ' + smsg); + s.put("

"); + html_encode(s, descr); + s.put("

\n"); + std_html_footer(s); + } + + // send the response + begin_response(code, msg); + if (s.tell() > 0) // some responses do not return any content, e.g. 304 + { + put_content_type("text/html"); + put_content_length(s.tell()); + } + end_headers(); + if (s.tell() > 0) + sockout->put(s.get_strdata()); + + end_response(); +} + + +void request_rec::std_response(bool conn_close, int code, const char* msg, const char* descr, const string& dparam) +{ + char buf[1024]; + snprintf(buf, sizeof(buf), descr, pconst(dparam)); + std_response(conn_close, code, msg, buf); +} + + +void request_rec::rsp_not_found() +{ + std_response(false, 404, "Not found", "The requested object %s was not found on this server.", url.path); +} + + +void request_rec::rsp_bad_request() +{ + std_response(true, 400, "Bad request", "Your browser sent a request that this server could not understand."); +} + + +void request_rec::rsp_bad_method(const char* ok_methods) +{ + put_header("Allow", ok_methods); + std_response(true, 405, "Method not allowed", "Method %s not allowed for this resource", method_str); +} + + +void request_rec::rsp_uri_too_long() +{ + std_response(true, 414, "Request-URI too long", "The request-URI string sent by your browser is too long."); +} + + +void request_rec::rsp_forbidden() +{ + std_response(false, 403, "Forbidden", "You don't have permission to access %s on this server", url.path); +} + + +void request_rec::rsp_dir_index_forbidden() +{ + std_response(false, 403, "Directory index forbidden", "Directory index forbidden: %s", url.path); +} + + +void request_rec::rsp_redirect(const string& newurl) +{ + location = newurl; + std_response(false, 301, "Moved permanently", "The document has moved to %s", newurl); +} + + +void request_rec::rsp_overloaded() +{ + std_response(true, 503, "Service unavailable", "The server is overloaded. Please, try again later."); +} + + +void request_rec::rsp_not_modified() +{ + std_response(false, 304, "Not modified", ""); +} + + +void request_rec::abort_request() +{ +#ifdef DEBUG + syslog_write(SYSLOG_WARNING, "Request from %s aborted", pconst(iptostring(client_ip))); +#endif + keep_alive = false; + throw ehttp(0); +} + + +void request_rec::end_response() +{ + throw ehttp(rsp_code); +} + + +// +// request parsers +// + +const cset method_chars = "A-Z"; +const cset uri_chars = "~21-~FF"; +const cset field_chars = uri_chars - cset(":"); +const cset ws_chars = "~20"; + + +string request_rec::get_token(const cset& chars) +{ + char buf[MAX_TOKEN]; + int bufsize = sockin->token(chars, buf, sizeof(buf)); + if (bufsize == 0 || bufsize >= MAX_TOKEN) + rsp_bad_request(); + return string(buf, bufsize); +} + + +string request_rec::get_uri() +{ + char buf[MAX_REQUEST_URI]; + int bufsize = sockin->token(uri_chars, buf, sizeof(buf)); + if (bufsize == 0) + rsp_bad_request(); + if (bufsize >= MAX_REQUEST_URI) + rsp_uri_too_long(); + return string(buf, bufsize); +} + + +void request_rec::parse_method() +{ + while (!sockin->get_eof() && sockin->get_eol()) + sockin->skipline(); + method_str = get_token(method_chars); + req_line = method_str; + + // try to pass this method to a registered method handler. + // the rest of the request line can be parsed using + // parse_request_line(), if it's HTTP/1.1-like. + handler_info* h = find_method_handler(method_str); + if (h != 0) + { + method_callback(h->callback)(*this); + // the handler must throw an ehttp exception + fatal(252, "Internal error 252"); + } + // otherwise use the internal method handlers + else if (method_str == "GET") + method = HTTP_GET; + else if (method_str == "HEAD") + method = HTTP_HEAD; + else if (length(method_str) == 0) + abort_request(); + else + rsp_bad_method("GET, HEAD"); +} + + +void request_rec::parse_request_line() +{ + if (sockin->skiptoken(ws_chars) == 0) + abort_request(); + + // read the request URI + uri = get_uri(); + req_line += ' ' + uri; + + // read the version number, if present + if (sockin->get_eol()) + version = HTTP_VER_09; + else + { + string s; + + if (sockin->skiptoken(ws_chars) == 0) + abort_request(); + s = get_token(uri_chars); + req_line += ' ' + s; + const char* p = s; + if (length(s) < 8 || strncmp(p, "HTTP/1.", 7) != 0) + rsp_bad_request(); + if (p[7] == '0') + version = HTTP_VER_10; + else if (p[7] == '1') + version = HTTP_VER_11; + else + version = HTTP_VER_UNKNOWN; // 1.x is ok for us + } + + // HTTP/1.1 requires to keep the connection alive by default; + // can be overridden by `Connection:' header + keep_alive = version >= HTTP_VER_11; + + if (!sockin->get_eol()) + rsp_bad_request(); + + if (version > HTTP_VER_09) + sockin->skipline(); +} + + +void request_rec::parse_hdr(string& fname, string& fvalue) +{ + fname = get_token(field_chars); // read the field name + sockin->skiptoken(ws_chars); + if (sockin->get() != ':') // malformed header (no colon) + rsp_bad_request(); + + do { + sockin->skiptoken(ws_chars); // skip leading ws chars + do { + if (sockin->get_eol()) // the value may be empty (?) + break; + string t = get_token(uri_chars); // read field value + if (!isempty(fvalue)) + fvalue += ' '; + fvalue += t; + if (length(fvalue) > MAX_TOKEN) + rsp_bad_request(); + // according to RFC2616 all ws chars inside the field value + // can become a single space + } while (sockin->skiptoken(ws_chars) > 0); + + if (!sockin->get_eol()) + rsp_bad_request(); + sockin->skipline(); + } while (sockin->preview() & ws_chars); // see if field value continues on the next line +} + + +void request_rec::parse_headers() +{ + while (!sockin->get_eol()) + { + string fname, fvalue; + parse_hdr(fname, fvalue); + fname = lowercase(fname); + + if (fname == "host") + host = fvalue; + + else if (fname == "connection") + { + fvalue = lowercase(fvalue); + if (fvalue == "close") + keep_alive = false; + else if (fvalue == "keep-alive") + keep_alive = true; + } + + else if (fname == "if-modified-since") + { + if_modified = parse_http_date(fvalue); + if (if_modified == invdatetime) + rsp_bad_request(); + } + + else if (fname == "referer") + referer = fvalue; + + else if (fname == "range") + { + if (strncmp(fvalue, "bytes=", 6) == 0) + { + del(fvalue, 0, 6); + const char* p = fvalue; + char* e; + int rmin = strtol(p, &e, 10); + if (*e == '-') + { + p = e + 1; + int rmax = strtol(p, &e, 10); + if (e == p) + rmax = -1; + // we don't support multiple ranges, neither negative ranges + if (*e == 0 && rmin >= 0) + { + partial = true; + range_min = rmin; + range_max = rmax; + } + } + } + } + + // other headers go to request_rec::headers for use in + // custom plugins/modules. so called "coalesce" headers + // are not supported yet + else + headers.put(fname, fvalue); + } + + // convert the referer URI to relative if on the same host + if (!isempty(referer)) + { + string s = "http://" + host; + if (strncmp(s, referer, length(s)) == 0) + del(referer, 0, length(s)); + if (isempty(referer)) + referer = "/"; + } + + sockin->skipline(); +} + + +void request_rec::parse_uri() +{ + string s = uri; + if (!isurl(uri)) + { + // if request URI is just a path + if (*pconst(uri) != '/') + rsp_bad_request(); + if (version > HTTP_VER_09 && isempty(host)) + rsp_bad_request(); + s = "http://" + host + uri; + } + + urlcrack(s, url); + + // split the path into components + split_path(url.path, path_parts); +} + + +void request_rec::analyze_uri() +{ + // analyze path components one by one and stop at the longest + // match that has a path handler. note that the request-uri + // may be longer and may contain extra components which are + // ignored, but left intact to be used by the handler. + + string path = "/"; + handler_info* handler = find_path_handler(path); + + for (int i = 0; i < path_parts.get_count(); i++) + { + path += path_parts.getkey(i); + handler_info* h = find_path_handler(path); + if (h != 0) + handler = h; + path += "/"; + } + + if (handler == 0) + rsp_not_found(); + + path_callback(handler->callback)(*this); + // the handler must throw an ehttp exception + fatal(253, "Internal error 253"); +} + + +void request_rec::respond() +{ + try + { + if (thread_count > cfg_max_clients) + rsp_overloaded(); + + parse_method(); + parse_request_line(); + parse_headers(); + parse_uri(); + analyze_uri(); + + // all branches must throw an ehttp exception + // before reaching this point + fatal(254, "Internal error 254"); + } + + catch(ehttp e) + { + if (keep_alive) + { + sockout->flush(); + stat = STAT_WAIT; + } + else + { + sockin->close(); + sockout->close(); + } + + htlog_write(client_ip, req_line, e.code, sockout->tellx() - hdr_size, referer); + } +} + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/request.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/request.h Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,168 @@ +/* + * + * 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 W_REQUEST_H +#define W_REQUEST_H + + +#include +#include +#include + +#include "sysutils.h" +#include "urlutils.h" + + +USING_PTYPES + + +enum http_version_t { + HTTP_VER_09, + HTTP_VER_10, + HTTP_VER_11, + HTTP_VER_UNKNOWN, + HTTP_VER_MAX +}; + + +enum http_method_t { + HTTP_GET, + HTTP_HEAD, + HTTP_OTHER, + HTTP_METHOD_MAX +}; + + +enum req_stat_t +{ + STAT_READ, + STAT_WRITE, + STAT_WAIT, + STAT_MAX +}; + + +struct ehttp +{ + int code; + ehttp(int icode): code(icode) {} +}; + + +class request_rec +{ +public: + datetime started; + int rsp_code; // rsp: response code, set through begin_response(), used for logging + req_stat_t stat; // for status requests: READ, WRITE or WAIT (if keep-alive) + instm* sockin; // client input stream + outstm* sockout; // client output stream + ipaddress client_ip; // req: client's IP + http_version_t version; // req/rsp: HTTP version, 0.9, 1.0, 1.1 or 1.* + http_method_t method; // req: HTTP method, currently GET or HEAD + string method_str; // method string, for other method handlers + bool keep_alive; // req/rsp: whether to close the connection; determined + // based on the HTTP version and the "Connection:" header; + // can be forced to false for some response types, e.g. 400 Bad Request + datetime if_modified; // req: "If-modified-since:" if present, invdatetime otherwise + string req_line; // req: the whole request line, e.g. "GET / HTTP/1.1" + string uri; // req: request-URI, as is + string host; // req: "Host:" header, if present + string referer; // req: "Referer:"; may be converted to relative URI + bool partial; // req: partial content requested (see rsp_file()) + large range_min; // req: partial content + large range_max; // req: partial content + textmap headers; // other headers + + // requested object info + urlrec url; // req: the request-URI parsed and split into components + strlist path_parts; // request-URI path split into components + + unknown* user; // user data for custom handlers, freed automatically by ~request_rec() + + // helpers for method handlers + string get_token(const cset& chars); + string get_uri(); + void parse_request_line(); // ... excluding the method string + void parse_hdr(string& fname, string& fvalue); + void parse_uri(); // sets url and path_parts fields + void analyze_uri(); // sets all fields starting from file_type + + // response utilities; headers are not sent if the HTTP version is 0.9 + void begin_response(int code, const char* msg); + + void put_header(const char* name, const char* value); + void put_header(const char* name, const string& value); + void put_content_type(const char* mime); + void put_content_length(large length); + void end_headers(); + void std_response(bool conn_close, int code, const char* msg, const char* descr); + void std_response(bool conn_close, int code, const char* msg, const char* descr, const string& dparam); + + // standard responses; all functions of this group raise ehttp exceptions + void rsp_not_found(); + void rsp_bad_request(); + void rsp_bad_method(const char* ok_methods); + void rsp_uri_too_long(); + void rsp_forbidden(); + void rsp_dir_index_forbidden(); + void rsp_overloaded(); + void abort_request(); + void rsp_redirect(const string& newurl); + void rsp_not_modified(); + + void end_response(); + +protected: + string location; // rsp: add "Location:" header to the response; set through + // rsp_redirect() + int hdr_size; // byte size of response headers; used for logging, to determine + // the actual response content length (see respond()) + + // request parsers + void parse_method(); + void parse_headers(); + + // the boss + void respond(); + + // reset the state between requests when keep-alive + void reset_state(); + + request_rec(instm& isockin, outstm& isockout, ipaddress iclient_ip); + ~request_rec(); +}; + + +// this structure is created and handled in mod_file, however, we +// declare it here since this information can be passed to the +// file extension handlers. + +class file_request_rec +{ +public: + file_type_t file_type; // file, directory or other (device or pipe) + bool sym_link; // the object is a symbolic link (Unix only) + bool executable; // the object is executable (binary on Unix, .exe on Windows) + string abs_path; // absolute file path to the requested object + string rel_path; // file path to the requested object relative to document root, + // may not be the same as url.path + string file_name; // file name + string file_ext; // file extension, including the leading dot + + file_request_rec(): file_type(FT_ERROR), sym_link(false), executable(false), + abs_path(), rel_path(), file_name(), file_ext() {} + ~file_request_rec() {} +}; + + +#endif diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/sysutils.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/sysutils.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,418 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include +#include +#include +#include + +#ifdef WIN32 +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include + +#include "sysutils.h" +#include "utils.h" + + +USING_PTYPES + + +void throw_msg(const string& msg) +{ + throw new exception(msg); +} + + +static char* nodename = 0; +static char* username = 0; + + +char* get_nodename() +{ + if (nodename == 0) + { +#ifdef WIN32 + char buf[MAX_COMPUTERNAME_LENGTH + 1]; + unsigned long bufsize = sizeof(buf); + if (!GetComputerName(buf, &bufsize)) + fatal(1001, "GetComputerName() failed"); + nodename = strdup(buf); +#else + struct utsname u; + if (uname(&u) < 0) + fatal(1001, "Couldn't get the node name"); + nodename = strdup(u.nodename); +#endif + } + return nodename; +} + + +char* get_username() +{ + if (username == 0) + { +#ifdef WIN32 + char buf[256 + 1]; + unsigned long bufsize = sizeof(buf); + if (!GetUserName(buf, &bufsize)) + fatal(1002, "GetUserName() failed"); + username = strdup(buf); +#else + struct passwd* pw = getpwuid(getuid()); + if (pw == 0) + fatal(1001, "Couldn't get the user name"); + username = strdup(pw->pw_name); +#endif + } + return username; +} + + +#ifdef WIN32 +int get_user_id(const char*) +{ + return 0; +#else +int get_user_id(const char* user_name) +{ + struct passwd* pw = getpwnam(user_name); + if (pw == 0) + return -1; + else + return pw->pw_uid; +#endif +} + + +#ifdef WIN32 +int get_user_gid(const char*) +{ + return 0; +#else +int get_user_gid(const char* user_name) +{ + struct passwd* pw = getpwnam(user_name); + if (pw == 0) + return -1; + else + return pw->pw_gid; +#endif +} + + +#ifdef WIN32 +int get_group_id(const char*) +{ + return 0; +#else +int get_group_id(const char* group_name) +{ + struct group* gr = getgrnam(group_name); + if (gr == 0) + return -1; + else + return gr->gr_gid; +#endif +} + + +#ifdef WIN32 +string get_group_name(int) +{ + return nullstring; +#else +string get_group_name(int gid) +{ + struct group* gr = getgrgid(gid); + if (gr == 0) + return nullstring; + else + return gr->gr_name; +#endif +} + + +file_type_t get_file_type(const char* name) +{ + struct stat st; + if (stat(name, &st) != 0) + return FT_ERROR; + if ((st.st_mode & S_IFDIR) == S_IFDIR) + return FT_DIRECTORY; + if ((st.st_mode & S_IFREG) == S_IFREG) + return FT_FILE; + return FT_OTHER; +} + + +#ifdef WIN32 +bool is_symlink(const char*) +{ + return false; +#else +bool is_symlink(const char* name) +{ + struct stat st; + if (lstat(name, &st) != 0) + return false; + return (st.st_mode & S_IFLNK) == S_IFLNK; +#endif +} + + + +#ifdef WIN32 +bool is_executable(const char* name) +{ + return stricmp(get_file_ext(name), ".exe") == 0; +#else +bool is_executable(const char* name) +{ + struct stat st; + if (stat(name, &st) != 0) + return false; + return (st.st_mode & S_IXOTH) == S_IXOTH; +#endif +} + + + +large get_file_size(const char* name) +{ +#ifdef WIN32 + struct __stat64 st; + if (_stat64(name, &st) != 0) +#else + struct stat st; + if (stat(name, &st) != 0) +#endif + return -1; + return st.st_size; +} + + +datetime get_file_mtime(const char* name) +{ + struct stat st; + if (stat(name, &st) != 0) + return invdatetime; + return utodatetime(st.st_mtime); +} + + +#if defined(__sun__) || defined(__hpux) + + +int daemon(int nochdir, int noclose) { + int fd; + + switch (fork()) + { + case -1: + return -1; + case 0: + break; + default: + exit(0); + } + + if (setsid() == -1) + return -1; + + if (!nochdir) + chdir("/"); + + if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) + { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > 2) + close(fd); + } + return 0; +} + + +#elif defined WIN32 + + +int daemon(int nochdir, int) +{ + if (!nochdir) + chdir("/"); + return 0; +} + + +#endif + + +#ifdef WIN32 +void downgrade(const string&, string&) +{ +#else +void downgrade(const string& user, string& group) +{ + int uid = get_user_id(user); + if (uid < 0) + throw_msg("Unknown user: " + user); + + int gid; + if (isempty(group)) + { + gid = get_user_gid(user); + group = get_group_name(gid); + } + else + gid = get_group_id(group); + + if (gid < 0) + throw_msg("Unknown group: " + group); + + if (setgid(gid) < 0) + throw_msg("Couldn't change effective user/group ID (not root?)"); + if (initgroups(user, gid)) + throw_msg("initgroups() failed"); // what else can we say here? + if (setuid(uid) < 0) + throw_msg("Couldn't change effective user ID (not root?)"); +#endif +} + + +file_info::file_info(const char* iname, large isize, datetime imodified) + : name(iname), size(isize), modified(imodified) {} + + +void get_directory(filist& s, string path, bool dirs, int maxfiles) +{ +#ifdef WIN32 + path += "*.*"; + _finddatai64_t f; + int h = _findfirsti64((char*)pconst(path), &f); // this stupid typecast is for BCC + if (h < 0) + return; + do + { + if (((f.attrib & _A_SUBDIR) != 0) == dirs) + { + string t = f.name; + if (t == '.') + continue; + if (dirs) + t += '/'; + s.add(t, new file_info(t, f.size, utodatetime(f.time_write))); + } + } + while (_findnexti64(h, &f) == 0 && s.get_count() < maxfiles); + _findclose(h); + +#else + if (path != '/' && trail_char(path) == '/') + trunc_trail_char(path); + DIR* dir = opendir(path); + if (dir == 0) + return; + dirent* de; + while ((de = readdir(dir)) != 0 && s.get_count() < maxfiles) + { + string name = de->d_name; + if (name == '.') + continue; + string fullname = path + '/' + name; + +#if defined(__sun__) || defined(__hpux) || defined(__CYGWIN__) + file_type_t ft = get_file_type(fullname); + if ((ft == FT_DIRECTORY) != dirs) + continue; + if (ft != FT_DIRECTORY && ft != FT_FILE && !is_symlink(fullname)) + continue; +#else + if ((de->d_type == DT_DIR) != dirs) + continue; + if (de->d_type != DT_DIR && de->d_type != DT_REG && de->d_type != DT_LNK) + continue; +#endif + + large size = 0; + if (dirs) + name += '/'; + else + size = get_file_size(fullname); + datetime mtime = get_file_mtime(fullname); + s.add(name, new file_info(name, size, mtime)); + } + closedir(dir); +#endif +} + + +string absolute_path(const string& rel) +{ + string abs; + +#ifdef WIN32 + setlength(abs, 4096); + char* p = unique(abs); + _fullpath(p, rel, 4096); + while (*p != 0) + { + if (*p == '\\') + *p = '/'; + p++; + } +#else +# ifdef PATH_MAX + int path_max = PATH_MAX; +# else + int path_max = pathconf(path, _PC_PATH_MAX); + if (path_max <= 0) + path_max = 4096; +# endif + setlength(abs, path_max); + char* p = unique(abs); + realpath(rel, p); +#endif + + return pconst(abs); +} + + +string get_file_ext(const string& name) +{ + const char* e = pconst(name) + length(name); + int len = 0; + while (e > pconst(name) && *e != '.' && *e != '/') + { + e--; + len++; + } + if (*e == '.' && len > 1) + return string(e, len); + else + return emptystr; +} + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/sysutils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/sysutils.h Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,77 @@ +/* + * + * 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 W_SYSUTILS_H +#define W_SYSUTILS_H + +#ifndef WIN32 +# include +#endif + +#include +#include +#include + + +USING_PTYPES + + +enum file_type_t +{ + FT_FILE, + FT_DIRECTORY, + FT_OTHER, // device or pipe + FT_ERROR = -1 +}; + + +class file_info +{ +public: + string name; + large size; + datetime modified; + file_info(const char* iname, large isize, datetime imodified); +}; + + +typedef tstrlist filist; + + +char* get_nodename(); +char* get_username(); +int get_user_id(const char* user_name); +int get_user_gid(const char* user_name); +int get_group_id(const char* group_name); +string get_group_name(int gid); + +file_type_t get_file_type(const char*); +bool is_symlink(const char*); +bool is_executable(const char*); +large get_file_size(const char*); +datetime get_file_mtime(const char*); +void get_directory(filist& s, string path, bool dirs, int maxfiles); +string absolute_path(const string& rel); +string get_file_ext(const string& name); + + +inline bool is_directory(const char* name) { return get_file_type(name) == FT_DIRECTORY; } +inline bool is_file(const char* name) { return get_file_type(name) == FT_FILE; } + + +#if defined(__sun__) || defined(__hpux) || defined(WIN32) +int daemon(int nochdir, int noclose); +#endif + +void downgrade(const string& user, string& group); + +#endif diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/urlutils.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/urlutils.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,321 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include + +#include +#include + +#include "urlutils.h" + + +USING_PTYPES + + +char* opt_anonymous_username = "ftp"; +char* opt_anonymous_password = "unknown@"; +char* opt_default_urlscheme = "http"; + + +static cset schemechars("0-9A-Za-z~-."); + +// TODO: make these sets RFC2396-compliant +static cset unsafechars("~00-~20%:/@?#;\\<>+\"'~7F-~FF"); +static cset unsafepathchars = unsafechars - '/'; +static cset unsafeparamchars = unsafechars; +static cset pathtermchars("~00#?;"); + + +bool isurl(const string& s) +{ + const char* p = pconst(s); + const char* b = p; + while (*p & schemechars) + p++; + return p > b && *p == ':'; +} + + +static string urlencode(const string& s, const cset& unsafe) +{ + static const char hexchars[17] = "0123456789ABCDEF"; + + int numunsafe = 0; + const char* p; + for (p = s; *p != 0; p++) + if (*p & unsafe) + numunsafe++; + if (numunsafe == 0) + return s; + + string ret; + setlength(ret, length(s) + numunsafe * 2); + p = s; + char* d = unique(ret); + for (; *p != 0; p++, d++) + { + if (*p & unsafe) + { + *d++ = '%'; + *d++ = hexchars[*p >> 4]; + *d = hexchars[*p & 0x0f]; + } + else + *d = *p; + } + return ret; +} + + +string urlencodepath(const string& path) +{ + return urlencode(path, unsafepathchars); +} + + +static int urldefport(const string& scheme) +{ + if (scheme == "http") + return 80; + else if (scheme == "https") + return 443; + else if (scheme == "ftp") + return 21; + else + return 0; +} + + +urlrec::urlrec() + : scheme(), username(), password(), pwdset(false), host(), + port(0), path(), proto(), query(), fragment() {} + + +void urlclear(urlrec& u) +{ + clear(u.scheme); + clear(u.username); + clear(u.password); + u.pwdset = false; + clear(u.host); + u.port = 0; + clear(u.path); + clear(u.proto); + clear(u.query); + clear(u.fragment); +} + + +// urlcreate: +// NOTES: if scheme is empty, opt_default_urlscheme is taken; for ftp scheme +// leading '/' in the path component is significant; for all other schemes +// the leading '/' is ignored. + +string urlcreate(const urlrec& u) +{ + string ret; + string s, p; + + // scheme + if (isempty(u.scheme)) + s = opt_default_urlscheme; + else + s = lowercase(u.scheme); + if (s[length(s) - 1] == ':') + setlength(s, length(s) - 1); + ret = s + "://"; + + // username and password + if (!isempty(u.username)) + { + ret += urlencode(u.username, unsafechars); + if (u.pwdset) + ret += ':' + urlencode(u.password, unsafechars); + ret += '@'; + } + + // host name and port number + ret += u.host; + if (u.port != 0 && u.port != urldefport(s)) + ret += ':' + itostring(u.port); + + // path + ret += '/'; + p = u.path; + if (!isempty(p) && p[0] == '/') + { + if (s == "ftp") + ret += "%2F"; + del(p, 0, 1); + } + ret += urlencode(p, unsafepathchars); + + // params + if (!isempty(u.proto)) + ret += ';' + urlencode(u.proto, unsafeparamchars); + if (!isempty(u.query)) + ret += '?' + urlencode(u.query, unsafeparamchars); + if (!isempty(u.fragment)) + ret += '#' + urlencode(u.fragment, unsafeparamchars); + + return ret; +} + + +// urlcrack: +// Note: no "friendly" URL's! If the URL is invalid the result is undefined. + +static int xchartoint(char c) +{ + if (c >= 'a') + return c - 'a' + 10; + else if (c >= 'A') + return c - 'A' + 10; + else + return c - '0'; +} + + +static void assignurlstr(string& s, const char* p, const char* end, bool decodeplus = false) +{ + if (p >= end) + clear(s); + else + { + setlength(s, end - p); + char* d = unique(s); + for (; p < end; p++, d++) + { + if (*p == '+' && decodeplus) + *d = ' '; + else if (*p == '%') + { + if (++p == end) break; + *d = char(xchartoint(*p) << 4); + if (++p == end) break; + *d |= char(xchartoint(*p)); + } + else + *d = *p; + } + setlength(s, d - pconst(s)); + } +} + + +static void crackpath(const char* p, urlrec& u) +{ + const char* end = p; + while (!(*end & pathtermchars)) // [#0, '?', '#', ';'] + end++; + assignurlstr(u.path, p, end); + + // leading '/' + if (u.scheme == "http" || u.scheme == "https") + { + if (isempty(u.path)) + u.path = '/'; + else if (*pconst(u.path) != '/' && *pconst(u.path) != '~') + ins('/', u.path, 0); + } + + // parameters + while (*end != 0) + { + char paramtype = *end; + p = ++end; + while (!(*end & pathtermchars)) + end++; + switch(paramtype) + { + case ';': + assignurlstr(u.proto, p, end); + break; + case '?': + assignurlstr(u.query, p, end, true); + break; + case '#': + assignurlstr(u.fragment, p, end); + break; + } + } +} + + +void urlcrack(const string& s, urlrec& u) +{ + urlclear(u); + + const char* t; + const char* p = s; + const char* end = p; + + // scheme + while (*end & schemechars) + end++; + if (*end != ':' || *(end + 1) != '/' || *(end + 2) != '/') + return; // invalid scheme: we don't want to generate errors + assignurlstr(u.scheme, p, end); + u.scheme = lowercase(u.scheme); + end += 3; // skip '://' + + // hostname and possibly username:password + p = end; + while (*end != 0 && *end != '/' && *end != '@') + end++; + + // username and possibly password + if (*end == '@') + { + t = p; + while (*t != ':' && *t != '@') + t++; + // password + if (*t == ':') + { + assignurlstr(u.password, t + 1, end); + u.pwdset = true; + } + // username + assignurlstr(u.username, p, t); + end++; + p = end; + while (*end != 0 && *end != '/') + end++; + } + else if (u.scheme == "ftp") + { + u.username = opt_anonymous_username; + u.password = opt_anonymous_password; + u.pwdset = true; + } + + // hostname and possibly port number + t = p; + while (*t != 0 && *t != ':' && *t != '/') + t++; + assign(u.host, p, t - p); + + // port + if (*t == ':') + { + string s; + assign(s, t + 1, end - t - 1); + u.port = atoi(s); + } + + // path + if (*end == '/') + end++; + crackpath(end, u); +} + + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/urlutils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/urlutils.h Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,60 @@ +/* + * + * 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 W_URLUTILS_H +#define W_URLUTILS_H + + +#include +#include + + +USING_PTYPES + + +// +// URL utilities +// +// URL ::= ://[][[:]]/[][] +// ::= [:]@ +// ::= [ ; ] [ ? ] [ # ] +// + + +struct urlrec { + string scheme; // 'http', 'ftp', 'file', ... + string username; // for ftp scheme defaults to opt_anonymous_username + string password; // for ftp scheme defaults to opt_anonymous_password + bool pwdset; // empty password and NO password is not the same! + string host; // Internet or NetBIOS host name + int port; // 0 = default for the given scheme + string path; // be careful with the leading '/' (RFC1738) + string proto; // ';' + string query; // '?' + string fragment; // '#' + + urlrec(); +}; + + +extern char* opt_anonymous_username; +extern char* opt_anonymous_password; +extern char* opt_default_urlscheme; + +bool isurl(const string& s); +void urlclear(urlrec& u); +string urlencodepath(const string& path); +string urlcreate(const urlrec& u); +void urlcrack(const string& s, urlrec& u); + + +#endif diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/utils.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/utils.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,279 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include +#include + +#include +#include + +#include "config.h" +#include "sysutils.h" +#include "utils.h" +#include "urlutils.h" + + +USING_PTYPES + + +char trail_char(const string& s) +{ + if (isempty(s)) + return 0; + else + return *(pconst(s) + length(s) - 1); +} + + +void trunc_trail_char(string& s) +{ + if (isempty(s)) + return; + else + setlength(s, length(s) - 1); +} + + + +static const cset htchars = "<>&\"~00"; + +void html_encode(outstm& s, const char* p) +{ + while (*p != 0) + { + const char* b = p; + while (!(*p & htchars)) + p++; + s.write(b, p - b); + switch (*p) + { + case '<': s.put("<"); break; + case '>': s.put(">"); break; + case '&': s.put("&"); break; + case '"': s.put("""); break; + case '\xa0': s.put(" "); break; + } + if (*p != 0) + p++; + } +} + + +void std_html_header(outstm& s, const string& title) +{ + s.put("\n"); + s.put(""); + html_encode(s, title); + s.put("\n"); + s.put(STD_CSS); + s.put("\n"); + s.put("


"); + html_encode(s, title); + s.put("

\n"); +} + + +void std_html_footer(outstm& s) +{ + s.put("


"); + s.put(SERVER_APP_NAME); + s.put(" at "); + s.put(cfg_server_name); + if (cfg_port != DEF_HTTP_PORT) + s.put(':' + itostring(cfg_port)); + s.put("

\n\n"); +} + + +void html_show_file_list(outstm& s, const filist& list) +{ + const int FSIZE_WIDTH = 5; + + for (int i = 0; i < list.get_count(); i++) + { + file_info* f = list[i]; + + s.put(dttostring(f->modified, "%d-%b-%Y %H:%M")); + s.put(" "); + + if (trail_char(f->name) != '/') + { + string t = itostring(f->size); + char c = ' '; + if (length(t) > FSIZE_WIDTH) + { + c = 'k'; + t = itostring(f->size / 1024); + if (length(t) > FSIZE_WIDTH) + { + c = 'M'; + t = itostring(f->size / 1024 / 1024); + } + } + + s.put(pad(t, FSIZE_WIDTH, ' ', false)); + s.put(c); + } + else + s.put(" - "); + + s.put(" "); + s.put("name)); + s.put("\">"); + html_encode(s, f->name); + s.put("\r\n"); + } +} + + +// +// splits a URI path into components and builds +// a list of directory names. also resolves './' +// and '../' references +// +void split_path(const char* path, strlist& list) +{ + list.clear(); + const char* e = path; + if (*e == '/') + e++; + const char* b = e; + while (*b != 0) + { + e = strchr(e, '/'); + if (e == nil) + e = path + strlen(path); + if (e > b) + { + string s(b, e - b); // directory name + if (s != '.') // ignore './' self-references + { + if (s == "..") // resolve '../' references + { + if (list.get_count() > 0) + list.del(list.get_count() - 1); + } + else + list.add(s, nil); + } + } + if (*e == '/') + e++; + b = e; + } +} + + +string get_mimetype(const string& path) +{ + string ext = get_file_ext(path); + if (isempty(ext)) + if (is_executable(path)) + return "application/octet-stream"; + else + return DEF_MIME_TYPE; + + const char** p = mimetypes; + while (*p != 0) + { + if (**p == '.' && ext == *p) + { + do { + p++; + } while (**p == '.'); + return *p; + } + p++; + } + + return "application/octet-stream"; +} + + +const cset digits = "0-9"; +const cset letters = "A-Za-z"; +const cset non_date_chars = cset("~20-~FF") - digits - letters; + +static const char* mnames[12] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +static const char* downames[7] = + {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + +datetime parse_http_date(const string& d) +{ + string s; + inmemory m(d); + m.open(); + + m.skiptoken(letters); // day of week + m.skiptoken(non_date_chars); + + s = m.token(digits); // day + if (length(s) == 0) + return invdatetime; + int day = atoi(s); + m.skiptoken(non_date_chars); + + s = m.token(letters); // month + setlength(s, 3); + int month = 0; + for (int i = 0; i < 12; i++) + { + if (s == mnames[i]) + { + month = i + 1; + break; + } + } + if (month == 0) + return invdatetime; + m.skiptoken(non_date_chars); + + s = m.token(digits); // year + if (length(s) == 0) + return invdatetime; + int year = atoi(s); + if (year < 50) + year += 2000; + else if (year < 100) + year += 1900; + m.skiptoken(non_date_chars); + + int hour = atoi(m.token(digits)); + m.get(); + int min = atoi(m.token(digits)); + m.get(); + int sec = atoi(m.token(digits)); + + return encodedate(year, month, day) + encodetime(hour, min, sec); +} + + +// #define HTTP_DATE_FMT "%a, %d %b %Y %H:%M:%S GMT" + +string http_time_stamp(datetime t) +{ + if (t == invdatetime) + t = now(true); + + int dow, year, month, day, hour, min, sec; + decodedate(t, year, month, day); + decodetime(t, hour, min, sec); + dow = dayofweek(t); + + char buf[128]; + snprintf(buf, sizeof(buf), "%s, %02d %s %04d %02d:%02d:%02d GMT", + downames[dow], day, mnames[month - 1], year, hour, min, sec); + + return buf; +} + diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/utils.h Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,41 @@ +/* + * + * 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 W_UTILS_H +#define W_UTILS_H + +#include +#include +#include + + +#ifndef W_SYSUTILS_H +# include "sysutils.h" +#endif + + +USING_PTYPES + + +char trail_char(const string& s); +void trunc_trail_char(string& s); +void html_encode(outstm& s, const char* p); +void std_html_header(outstm& s, const string& title); +void std_html_footer(outstm& s); +void html_show_file_list(outstm& s, const filist& list); +void split_path(const char* path, strlist& list); +string get_mimetype(const string& path); +datetime parse_http_date(const string& d); +string http_time_stamp(datetime t); + + +#endif diff -r 0000000000000000000000000000000000000000 -r 8edbcdac0d392b0987c2d1c24e6a17839bae6840 wshare/wshare.cxx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wshare/wshare.cxx Wed May 08 23:49:28 2013 -0500 @@ -0,0 +1,187 @@ +/* + * + * C++ Portable Types Library (PTypes) + * Version 2.1.1 Released 27-Jun-2007 + * + * Copyright (C) 2001-2007 Hovik Melikyan + * + * http://www.melikyan.com/ptypes/ + * + */ + +#include +#include + +#include "config.h" +#include "sysutils.h" +#include "log.h" +#include "utils.h" +#include "urlutils.h" +#include "request.h" +#include "clients.h" +#include "modules.h" + + +USING_PTYPES + + +class client_socket: public ipstream +{ +public: + client_socket(); +}; + + +client_socket::client_socket() + : ipstream() +{ + // sets both input and output buffer sizes; some BSD systems + // don't like large output buffers + set_bufsize(SOCKET_BUF_SIZE); +} + + +void fail(const char* msg) +{ + syslog_write(SYSLOG_ERROR, "%s", msg); + exit(2); +} + + +void run_server() +{ + ipstmserver server; + client_socket* client = new client_socket(); + + threads.set_capacity(cfg_max_clients * 2); + + try + { + // listen to all local addresses on cfg_port + server.bindall(cfg_port); + syslog_write(SYSLOG_WARNING, "started, user=%s, port=%d, dir=%s", + get_username(), cfg_port, pconst(cfg_document_root)); + + // try to listen on socket to give an error message + // before daemonizing + server.poll(-1, 0); + + started = now(); + + // daemonize (has no effect on WIN32) + if (cfg_daemonize) + { + errlog = 0; + daemon(0, 0); + } + + // run-as (downgrade process priveleges) + if (!isempty(cfg_user)) + { + try + { + downgrade(cfg_user, cfg_group); + } + catch(exception* e) + { + fail(e->get_message()); + delete e; + } + syslog_write(SYSLOG_WARNING, "running as %s:%s", + pconst(cfg_user), pconst(cfg_group)); + } + + while (true) + { + // wait infinitely for a connection request + server.serve(*client); + + if (client->get_active()) + { + if (thread_count >= cfg_max_clients * 2) + { + // critical situation: the number of threads is twice as + // more than allowed + client->close(); + syslog_write(SYSLOG_WARNING, "critical number of clients reached (%d * 2), aborting connection", cfg_max_clients); + } + + else + { + // start a new thread for this connection + client_thread* conn = new client_thread(client); + client = 0; + // start and forget; the thread object will free itself + conn->start(); + client = new client_socket(); + } + } + } + } + catch(estream* e) + { + fail("Server socket error: " + e->get_message()); + delete e; + } +} + + +void config_check() +{ + cfg_document_root = absolute_path(cfg_document_root); + if (trail_char(cfg_document_root) == '/') + { +#ifdef WIN32 + if (length(cfg_document_root) > 3) // "c:/" or "///" ? +#else + if (length(cfg_document_root) > 1) // "/" ? +#endif + trunc_trail_char(cfg_document_root); + } + if (isempty(cfg_document_root) || !is_directory(cfg_document_root)) + fail("Document root directory not found"); + + if (cfg_port <= 0) + fail("Invalid port number"); + + if (!isempty(cfg_log_file)) + { + htlog = new logfile(cfg_log_file, true); + try + { + htlog->open(); + } + catch (estream* e) + { + fail(e->get_message()); + delete e; + } + } + + else if (cfg_daemonize) + syslog_write(SYSLOG_WARNING, "daemon started without a HTTP access log"); + + if (cfg_max_clients <= 0) + fail("Invalid maximum number of clients"); + +} + + +int main(int argc, char* argv[]) +{ + cfg_server_name = get_nodename(); + + config_init(argc, argv); + log_init(); + config_check(); + init_handlers(); + + run_server(); + + // currently we never reach this point + log_done(); + config_done(); + + return 0; +} +