From b6e100b94b12f3f92ec025dc2363eaf7c0ee6662 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 10 Apr 2007 16:02:07 +0000 Subject: Well, we've got the basis of a workable unit test harness thing. There should be a few more add-ons to it, but it works just fine, and eventually it should cover command line options and creating logs, and possibly even provide output functionality so that output from tests can be logged and kept track of well. --- build.conf | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'build.conf') diff --git a/build.conf b/build.conf index 5c4dbb6..bc186f9 100644 --- a/build.conf +++ b/build.conf @@ -30,6 +30,22 @@ filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"): set "LDFLAGS" += "-L. -lbu++", input "src/{target}.cpp" +directoriesIn("src/unit","unit/"): + rule "exe", + target file, + requires "libbu++.a", + set "CXXFLAGS" += "-Isrc", + set "LDFLAGS" += "-L. -lbu++", + input filesIn("{fulldir}") filter regexp("^.*\\.cpp$") + +filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"): + rule "exe", + target file, + requires "libbu++.a", + set "CXXFLAGS" += "-Isrc", + set "LDFLAGS" += "-L. -lbu++", + input "src/{target}.cpp" + "tests/plugin": set "LDFLAGS" += "-ldl" rule "exe": -- cgit v1.2.3 From 530014a3cce53e86dce8917e98a4e86d02f176aa Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Thu, 26 Apr 2007 15:06:49 +0000 Subject: Merged Ito and put it in the BU namespace. I should probably clean up the formatting on the comments, some of the lines wrap, but I'm not too worried about it right now. I also fixed up the doxygen config and build.conf files so that everything is building nice and smooth now. --- Doxyfile | 4 +- build.conf | 26 ++++-- mkincs.sh | 5 ++ src/exceptions.cpp | 1 + src/exceptions.h | 1 + src/ito.cpp | 40 +++++++++ src/ito.h | 98 ++++++++++++++++++++ src/itoatom.h | 56 ++++++++++++ src/itocondition.cpp | 42 +++++++++ src/itocondition.h | 81 +++++++++++++++++ src/itomutex.cpp | 27 ++++++ src/itomutex.h | 61 +++++++++++++ src/itoqueue.h | 231 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.dox | 14 +++ src/serversocket.cpp | 148 +++++++++++++++++++++++++++++++ src/serversocket.h | 31 +++++++ src/socket.cpp | 16 +--- src/socket.h | 4 +- src/tests/itoqueue1.cpp | 110 +++++++++++++++++++++++ src/tests/itoqueue2.cpp | 83 +++++++++++++++++ 20 files changed, 1059 insertions(+), 20 deletions(-) create mode 100755 mkincs.sh create mode 100644 src/ito.cpp create mode 100644 src/ito.h create mode 100644 src/itoatom.h create mode 100644 src/itocondition.cpp create mode 100644 src/itocondition.h create mode 100644 src/itomutex.cpp create mode 100644 src/itomutex.h create mode 100644 src/itoqueue.h create mode 100644 src/main.dox create mode 100644 src/serversocket.cpp create mode 100644 src/serversocket.h create mode 100644 src/tests/itoqueue1.cpp create mode 100644 src/tests/itoqueue2.cpp (limited to 'build.conf') diff --git a/Doxyfile b/Doxyfile index 6c7412e..c3168fa 100644 --- a/Doxyfile +++ b/Doxyfile @@ -74,9 +74,9 @@ QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES -WARN_NO_PARAMDOC = NO +WARN_NO_PARAMDOC = YES WARN_FORMAT = "$file:$line: $text" -WARN_LOGFILE = +WARN_LOGFILE = Doxywarn #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- diff --git a/build.conf b/build.conf index bc186f9..c289205 100644 --- a/build.conf +++ b/build.conf @@ -1,13 +1,17 @@ # This is a build file for libbu++ -default action: check "libbu++.a" -"clean" action: clean targets() -"tests" action: check targets() filter regexp("^tests/.*$") -"all" action: check targets() -"fstring" action: check "tests/fstring" +default action: check group "lnhdrs", check "libbu++.a" +"tests" action: check group "lnhdrs", check group "tests" +"all" action: check group "lnhdrs", check targets() set "CXXFLAGS" += "-ggdb -Wall" +filesIn("src") filter regexp("^src/(.*)\\.h$", "src/bu/{re:1}.h"): + rule "hln", + group "lnhdrs", + target file, + input "src/{re:1}.h" + "libbu++.a": rule "lib", target file, @@ -17,6 +21,7 @@ set "CXXFLAGS" += "-ggdb -Wall" directoriesIn("src/tests","tests/"): rule "exe", target file, + group "tests", requires "libbu++.a", set "CXXFLAGS" += "-Isrc", set "LDFLAGS" += "-L. -lbu++", @@ -25,14 +30,18 @@ directoriesIn("src/tests","tests/"): filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"): rule "exe", target file, + group "tests", requires "libbu++.a", set "CXXFLAGS" += "-Isrc", set "LDFLAGS" += "-L. -lbu++", input "src/{target}.cpp" +["tests/itoqueue1", "tests/itoqueue2"]: set "LDFLAGS" += "-lpthread" + directoriesIn("src/unit","unit/"): rule "exe", target file, + group "tests", requires "libbu++.a", set "CXXFLAGS" += "-Isrc", set "LDFLAGS" += "-L. -lbu++", @@ -41,6 +50,7 @@ directoriesIn("src/unit","unit/"): filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"): rule "exe", target file, + group "tests", requires "libbu++.a", set "CXXFLAGS" += "-Isrc", set "LDFLAGS" += "-L. -lbu++", @@ -63,3 +73,9 @@ rule "cpp": produces "{re:1}.o", requires commandToList("g++ -M {CXXFLAGS} {match}", "make"), perform command("g++ {CXXFLAGS} -c -o {target} {match}") + +rule "hln": + matches regexp("src/(.*)\\.h"), + produces "src/bu/{re:1}.h", + perform command("ln -s ../{re:1}.h {target}") + diff --git a/mkincs.sh b/mkincs.sh new file mode 100755 index 0000000..6f72f89 --- /dev/null +++ b/mkincs.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +cd src/bu +rm * +for i in ../*.h; do ln -s $i; done diff --git a/src/exceptions.cpp b/src/exceptions.cpp index a512105..d9f4e70 100644 --- a/src/exceptions.cpp +++ b/src/exceptions.cpp @@ -5,6 +5,7 @@ namespace Bu { subExceptionDef( XmlException ) subExceptionDef( FileException ) + subExceptionDef( SocketException ) subExceptionDef( ConnectionException ) subExceptionDef( PluginException ) subExceptionDef( UnsupportedException ) diff --git a/src/exceptions.h b/src/exceptions.h index 3efa19f..f146b73 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -8,6 +8,7 @@ namespace Bu { subExceptionDecl( XmlException ) subExceptionDecl( FileException ) + subExceptionDecl( SocketException ) subExceptionDecl( ConnectionException ) subExceptionDecl( PluginException ) subExceptionDecl( UnsupportedException ) diff --git a/src/ito.cpp b/src/ito.cpp new file mode 100644 index 0000000..001ca06 --- /dev/null +++ b/src/ito.cpp @@ -0,0 +1,40 @@ +#include "ito.h" + +Bu::Ito::Ito() +{ +} + +Bu::Ito::~Ito() +{ +} + +bool Bu::Ito::start() +{ + nHandle = pthread_create( &ptHandle, NULL, threadRunner, this ); + + return true; +} + +bool Bu::Ito::stop() +{ + pthread_exit( &ptHandle ); + + return true; +} + +void *Bu::Ito::threadRunner( void *pThread ) +{ + return ((Ito *)pThread)->run(); +} + +bool Bu::Ito::join() +{ + pthread_join( ptHandle, NULL ); + return true; +} + +void Bu::Ito::yield() +{ + pthread_yield(); +} + diff --git a/src/ito.h b/src/ito.h new file mode 100644 index 0000000..01253f5 --- /dev/null +++ b/src/ito.h @@ -0,0 +1,98 @@ +#ifndef ITO_H +#define ITO_H + +#include + +namespace Bu +{ + /** + * Simple thread class. This wraps the basic pthread (posix threads) system in + * an object oriented sort of way. It allows you to create a class with + * standard member variables and callable functions that can be run in it's own + * thread, one per class instance. + *@author Mike Buland + */ + class Ito + { + public: + /** + * Construct an Ito thread. + */ + Ito(); + + /** + * Destroy an Ito thread. + */ + virtual ~Ito(); + + /** + * Begin thread execution. This will call the overridden run function, + * which will simply execute in it's own thread until the function exits, + * the thread is killed, or the thread is cancelled (optionally). The + * thread started in this manner has access to all of it's class variables, + * but be sure to protect possible multiple-access with ItoMutex objects. + *@returns True if starting the thread was successful. False if something + * went wrong and the thread has not started. + */ + bool start(); + + /** + * Forcibly kill a thread. This is not generally considered a good thing to + * do, but in those rare cases you need it, it's invaluable. The problem + * with stopping (or killing) a thread is that it stops it the moment you + * call stop, no matter what it's doing. The object oriented approach to + * this will help clean up any class variables that were used, but anything + * not managed as a member variable will probably create a memory leak type + * of situation. Instead of stop, consider using cancel, which can be + * handled by the running thread in a graceful manner. + *@returns True if the thread was stopped, false otherwise. When this + * function returns the thread may not have stopped, to ensure that the + * thread has really stopped, call join. + */ + bool stop(); + + /** + * The workhorse of the Ito class. This is the function that will run in + * the thread, when this function exits the thread dies and is cleaned up + * by the system. Make sure to read up on ItoMutex, ItoCondition, and + * cancel to see how to control and protect everything you do in a safe way + * within this function. + *@returns I'm not sure right now, but this is the posix standard form. + */ + virtual void *run()=0; + + /** + * Join the thread in action. This function performs what is commonly + * called a thread join. That is that it effectively makes the calling + * thread an the Ito thread contained in the called object one in the same, + * and pauses the calling thread until the called thread exits. That is, + * when called from, say, your main(), mythread.join() will not return until + * the thread mythread has exited. This is very handy at the end of + * programs to ensure all of your data was cleaned up. + *@returns True if the thread was joined, false if the thread couldn't be + * joined, usually because it isn't running to begin with. + */ + bool join(); + + private: + pthread_t ptHandle; /**< Internal handle to the posix thread. */ + int nHandle; /**< Numeric handle to the posix thread. */ + + protected: + /** + * This is the hidden-heard of the thread system. While run is what the + * user gets to override, and everything said about it is true, this is + * the function that actually makes up the thread, it simply calls the + * run member function in an OO-friendly way. This is what allows us to + * use member variables from within the thread itself. + *@param Should always be this. + *@returns This is specified by posix, I'm not sure yet. + */ + static void *threadRunner( void *pThread ); + + void yield(); + + }; +} + +#endif diff --git a/src/itoatom.h b/src/itoatom.h new file mode 100644 index 0000000..96090f2 --- /dev/null +++ b/src/itoatom.h @@ -0,0 +1,56 @@ +#ifndef ITO_QUEUE_H +#define ITO_QUEUE_H + +#include + +#include "itomutex.h" +#include "itocondition.h" + +/** + * A thread-safe wrapper class. + *@author Mike Buland + */ +template +class ItoAtom +{ +public: + /** + * Construct an empty queue. + */ + ItoAtom() + { + } + + ItoAtom( const T &src ) : + data( src ) + { + } + + ~ItoQueue() + { + } + + T get() + { + mOperate.lock(); + mOperate.unlock(); + return data; + } + + void set( const T &val ) + { + mOperate.lock(); + data = val; + cBlock.signal(); + mOperate.unlock(); + } + +private: + Item *pStart; /**< The start of the queue, the next element to dequeue. */ + Item *pEnd; /**< The end of the queue, the last element to dequeue. */ + + ItoMutex mOperate; /**< The master mutex, used on all operations. */ + ItoCondition cBlock; /**< The condition for blocking dequeues. */ +}; + +#endif diff --git a/src/itocondition.cpp b/src/itocondition.cpp new file mode 100644 index 0000000..d8f5375 --- /dev/null +++ b/src/itocondition.cpp @@ -0,0 +1,42 @@ +#include + +#include "itocondition.h" + +Bu::ItoCondition::ItoCondition() +{ + pthread_cond_init( &cond, NULL ); +} + +Bu::ItoCondition::~ItoCondition() +{ + pthread_cond_destroy( &cond ); +} + +int Bu::ItoCondition::wait() +{ + return pthread_cond_wait( &cond, &mutex ); +} + +int Bu::ItoCondition::wait( int nSec, int nUSec ) +{ + struct timeval now; + struct timespec timeout; + struct timezone tz; + + gettimeofday( &now, &tz ); + timeout.tv_sec = now.tv_sec + nSec + ((now.tv_usec + nUSec)/1000000); + timeout.tv_nsec = ((now.tv_usec + nUSec)%1000000)*1000; + + return pthread_cond_timedwait( &cond, &mutex, &timeout ); +} + +int Bu::ItoCondition::signal() +{ + return pthread_cond_signal( &cond ); +} + +int Bu::ItoCondition::broadcast() +{ + return pthread_cond_broadcast( &cond ); +} + diff --git a/src/itocondition.h b/src/itocondition.h new file mode 100644 index 0000000..4771b22 --- /dev/null +++ b/src/itocondition.h @@ -0,0 +1,81 @@ +#ifndef ITO_CONDITION_H +#define ITO_CONDITION_H + +#include + +#include "itomutex.h" + +namespace Bu +{ + /** + * Ito condition. This is a fairly simple condition mechanism. As you may + * notice this class inherits from the ItoMutex class, this is because all + * conditions must be within a locked block. The standard usage of a condition + * is to pause one thread, perhaps indefinately, until another thread signals + * that it is alright to procede. + *
+ * Standard usage for the thread that wants to wait is as follows: + *
+	 * ItoCondition cond;
+	 * ... // Perform setup and enter your run loop
+	 * cond.lock();
+	 * while( !isFinished() ) // Could be anything you're waiting for
+	 *     cond.wait();
+	 * ...  // Take care of what you have to.
+	 * cond.unlock();
+	 * 
+ * The usage for the triggering thread is much simpler, when it needs to tell + * the others that it's time to grab some data it calls either signal or + * broadcast. See both of those functions for the difference. + *@author Mike Buland + */ + class ItoCondition : public ItoMutex + { + public: + /** + * Create a condition. + */ + ItoCondition(); + + /** + * Destroy a condition. + */ + ~ItoCondition(); + + /** + * Wait forever, or until signalled. This has to be called from within a + * locked section, i.e. before calling this this object's lock function + * should be called. + */ + int wait(); + + /** + * Wait for a maximum of nSec seconds and nUSec micro-seconds or until + * signalled. This is a little more friendly function if you want to + * perform other operations in the thrad loop that calls this function. + * Like the other wait function, this must be inside a locked section. + *@param nSec The seconds to wait. + *@param nUSec the micro-seconds to wait. + */ + int wait( int nSec, int nUSec ); + + /** + * Notify the next thread waiting on this condition that they can go ahead. + * This only signals one thread, the next one in the condition queue, that + * it is safe to procede with whatever operation was being waited on. + */ + int signal(); + + /** + * Notify all threads waiting on this condition that they can go ahead now. + * This function is slower than signal, but more effective in certain + * situations where you may not know how many threads should be activated. + */ + int broadcast(); + + private: + pthread_cond_t cond; /**< Internal condition reference. */ + }; +} + +#endif diff --git a/src/itomutex.cpp b/src/itomutex.cpp new file mode 100644 index 0000000..dc51af9 --- /dev/null +++ b/src/itomutex.cpp @@ -0,0 +1,27 @@ +#include "itomutex.h" + +Bu::ItoMutex::ItoMutex() +{ + pthread_mutex_init( &mutex, NULL ); +} + +Bu::ItoMutex::~ItoMutex() +{ + pthread_mutex_destroy( &mutex ); +} + +int Bu::ItoMutex::lock() +{ + return pthread_mutex_lock( &mutex ); +} + +int Bu::ItoMutex::unlock() +{ + return pthread_mutex_unlock( &mutex ); +} + +int Bu::ItoMutex::trylock() +{ + return pthread_mutex_trylock( &mutex ); +} + diff --git a/src/itomutex.h b/src/itomutex.h new file mode 100644 index 0000000..80956b8 --- /dev/null +++ b/src/itomutex.h @@ -0,0 +1,61 @@ +#ifndef ITO_MUTEX_H +#define ITO_MUTEX_H + +#include + +namespace Bu +{ + /** + * Simple mutex wrapper. Currently this doesn't do anything extra for you + * except keep all of the functionality together in an OO sorta' way and keep + * you from having to worry about cleaning up your mutexes properly, or initing + * them. + *@author Mike Buland + */ + class ItoMutex + { + public: + /** + * Create an unlocked mutex. + */ + ItoMutex(); + + /** + * Destroy a mutex. This can only be done when a mutex is unlocked. + * Failure to unlock before destroying a mutex object could cause it to + * wait for the mutex to unlock, the odds of which are usually farily low + * at deconstruction time. + */ + ~ItoMutex(); + + /** + * Lock the mutex. This causes all future calls to lock on this instance + * of mutex to block until the first thread that called mutex unlocks it. + * At that point the next thread that called lock will get a chance to go + * to work. Because of the nature of a mutex lock it is a very bad idea to + * do any kind of serious or rather time consuming computation within a + * locked section. This can cause thread-deadlock and your program may + * hang. + */ + int lock(); + + /** + * Unlock the mutex. This allows the next thread that asked for a lock to + * lock the mutex and continue with execution. + */ + int unlock(); + + /** + * Try to lock the mutex. This is the option to go with if you cannot avoid + * putting lengthy operations within a locked section. trylock will attempt + * to lock the mutex, if the mutex is already locked this function returns + * immediately with an error code. + */ + int trylock(); + + protected: + pthread_mutex_t mutex; /**< The internal mutex reference. */ + }; +} + +#endif diff --git a/src/itoqueue.h b/src/itoqueue.h new file mode 100644 index 0000000..322698d --- /dev/null +++ b/src/itoqueue.h @@ -0,0 +1,231 @@ +#ifndef ITO_QUEUE_H +#define ITO_QUEUE_H + +#include + +#include "itomutex.h" +#include "itocondition.h" + +namespace Bu +{ + /** + * A thread-safe queue class. This class is a very simple queue with some cool + * extra functionality for use with the Ito system. The main extra that it + * provides is the option to either dequeue without blocking, with infinite + * blocking, or with timed blocking, which will return a value if something is + * enqueued within the specified time limit, or NULL if the time limit is + * exceded. + *@author Mike Buland + */ + template + class ItoQueue + { + private: + /** + * Helper struct. Keeps track of linked-list items for the queue data. + */ + typedef struct Item + { + T pData; + Item *pNext; + } Item; + + public: + /** + * Construct an empty queue. + */ + ItoQueue() : + pStart( NULL ), + pEnd( NULL ), + nSize( 0 ) + { + } + + /** + * Destroy the queue. This function will simply free all contained + * structures. If you stored pointers in the queue, this will lose the + * pointers without cleaning up the memory they pointed to. Make sure + * you're queue is empty before allowing it to be destroyed! + */ + ~ItoQueue() + { + Item *pCur = pStart; + while( pCur ) + { + Item *pTmp = pCur->pNext; + delete pCur; + pCur = pTmp; + } + } + + /** + * Enqueue a pieces of data. The new data will go at the end of the queue, + * and unless another piece of data is enqueued, will be the last piece of + * data to be dequeued. + *@param pData The data to enqueue. If this is not a primitive data type + * it's probably best to use a pointer type. + */ + void enqueue( T pData ) + { + mOperate.lock(); + + if( pStart == NULL ) + { + pStart = pEnd = new Item; + pStart->pData = pData; + pStart->pNext = NULL; + nSize++; + } + else + { + pEnd->pNext = new Item; + pEnd = pEnd->pNext; + pEnd->pData = pData; + pEnd->pNext = NULL; + nSize++; + } + + cBlock.signal(); + + mOperate.unlock(); + } + + /** + * Dequeue the first item from the queue. This function can operate in two + * different modes, blocking and non-blocking. In non-blocking mode it will + * return immediately weather there was data in the queue or not. If there + * was data it will remove it from the queue and return it to the caller. + * In blocking mode it will block forever wating for data to be enqueued. + * When data finally is enqueued this function will return immediately with + * the new data. The only way this function should ever return a null in + * blocking mode is if the calling thread was cancelled. It's probably a + * good idea to check for NULL return values even if you use blocking, just + * to be on the safe side. + *@param bBlock Set to true to enable blocking, leave as false to work in + * non-blocking mode. + *@returns The next piece of data in the queue, or NULL if no data was in + * the queue. + */ + T dequeue( bool bBlock=false ) + { + mOperate.lock(); + if( pStart == NULL ) + { + mOperate.unlock(); + + if( bBlock ) + { + cBlock.lock(); + + while( pStart == NULL ) + cBlock.wait(); + + T tmp = dequeue( false ); + + cBlock.unlock(); + return tmp; + + } + + return NULL; + } + else + { + T pTmp = pStart->pData; + Item *pDel = pStart; + pStart = pStart->pNext; + delete pDel; + nSize--; + + mOperate.unlock(); + return pTmp; + } + } + + /** + * Operates just like the other dequeue function in blocking mode with one + * twist. This function will block for at most nSec seconds and nUSec + * micro-seconds. If the timer is up and no data is available, this will + * just return NULL. If data is enqueued before the timeout expires, it + * will dequeue and exit immediately. + *@param nSec The number of seconds to wait, max. + *@param nUSec The number of micro-seconds to wait, max. + *@returns The next piece of data in the queue, or NULL if the timeout was + * exceeded. + */ + T dequeue( int nSec, int nUSec ) + { + mOperate.lock(); + if( pStart == NULL ) + { + mOperate.unlock(); + + cBlock.lock(); + + cBlock.wait( nSec, nUSec ); + + if( pStart == NULL ) + { + cBlock.unlock(); + return NULL; + } + + mOperate.lock(); + T pTmp = pStart->pData; + Item *pDel = pStart; + pStart = pStart->pNext; + delete pDel; + nSize--; + mOperate.unlock(); + + cBlock.unlock(); + return pTmp; + } + else + { + T pTmp = pStart->pData; + Item *pDel = pStart; + pStart = pStart->pNext; + delete pDel; + nSize--; + + mOperate.unlock(); + return pTmp; + } + } + + /** + * Checks to see if the queue has data in it or not. Note that there is no + * function to determine the length of the queue. This data isn't kept + * track of. If you really need to know, fix this. + *@returns True if the queue is empty, false if it has data in it. + */ + bool isEmpty() + { + mOperate.lock(); + bool bEmpty = (pStart == NULL ); + mOperate.unlock(); + + return bEmpty; + } + + long getSize() + { + mOperate.lock(); + long nRet = nSize; + mOperate.unlock(); + + return nRet; + } + + private: + Item *pStart; /**< The start of the queue, the next element to dequeue. */ + Item *pEnd; /**< The end of the queue, the last element to dequeue. */ + long nSize; /**< The number of items in the queue. */ + + ItoMutex mOperate; /**< The master mutex, used on all operations. */ + ItoCondition cBlock; /**< The condition for blocking dequeues. */ + }; +} + +#endif diff --git a/src/main.dox b/src/main.dox new file mode 100644 index 0000000..668d2e3 --- /dev/null +++ b/src/main.dox @@ -0,0 +1,14 @@ +/** + *@mainpage libbu++ utility library + * + *@section secIntro Introduction + * + * Libbu++ is a C++ library of general utility classes and functions. They + * cover a wide range of topics from streams and sockets to data structures to + * data serialization and xml handling to threading. + * + */ + +/** + *@namespace Bu The core libbu++ namespace, to ensure things don't get muddied. + */ diff --git a/src/serversocket.cpp b/src/serversocket.cpp new file mode 100644 index 0000000..c53c80d --- /dev/null +++ b/src/serversocket.cpp @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "serversocket.h" +#include "exceptions.h" + +Bu::ServerSocket::ServerSocket( int nPort, int nPoolSize ) : + nPort( nPort ) +{ + /* Create the socket and set it up to accept connections. */ + struct sockaddr_in name; + + /* Give the socket a name. */ + name.sin_family = AF_INET; + name.sin_port = htons( nPort ); + + // I think this specifies who we will accept connections from, + // a good thing to make configurable later on + name.sin_addr.s_addr = htonl( INADDR_ANY ); + + startServer( name, nPoolSize ); +} + +Bu::ServerSocket::ServerSocket(const FString &sAddr,int nPort, int nPoolSize) : + nPort( nPort ) +{ + /* Create the socket and set it up to accept connections. */ + struct sockaddr_in name; + + /* Give the socket a name. */ + name.sin_family = AF_INET; + name.sin_port = htons( nPort ); + + inet_aton( sAddr.getStr(), &name.sin_addr ); + + startServer( name, nPoolSize ); +} + +Bu::ServerSocket::~ServerSocket() +{ +} + +void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) +{ + /* Create the socket. */ + nServer = socket( PF_INET, SOCK_STREAM, 0 ); + if( nServer < 0 ) + { + throw Bu::SocketException("Couldn't create a listen socket."); + } + + int opt = 1; + setsockopt( + nServer, + SOL_SOCKET, + SO_REUSEADDR, + (char *)&opt, + sizeof( opt ) + ); + + if( bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 ) + { + throw Bu::SocketException("Couldn't bind to the listen socket."); + } + + if( listen( nServer, nPoolSize ) < 0 ) + { + throw Bu::SocketException( + "Couldn't begin listening to the server socket." + ); + } + + FD_ZERO( &fdActive ); + /* Initialize the set of active sockets. */ + FD_SET( nServer, &fdActive ); +} + +int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) +{ + fd_set fdRead = fdActive; + + struct timeval xT; + + xT.tv_sec = nTimeoutSec; + xT.tv_usec = nTimeoutUSec; + + if( TEMP_FAILURE_RETRY(select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 ) + { + throw SocketException( + "Error scanning for new connections: %s", strerror( errno ) + ); + } + + if( FD_ISSET( nServer, &fdRead ) ) + { + struct sockaddr_in clientname; + size_t size; + int nClient; + + size = sizeof( clientname ); +#ifdef __CYGWIN__ + nClient = ::accept( nServer, (struct sockaddr *)&clientname, + (int *)&size + ); +#else + nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size ); +#endif + if( nClient < 0 ) + { + throw SocketException( + "Error accepting a new connection: %s", strerror( errno ) + ); + } + char tmpa[20]; + inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 ); + //"New connection from host %s, port %hd.", + // tmpa, ntohs (clientname.sin_port) ); + + { + int flags; + + flags = fcntl( nClient, F_GETFL, 0 ); + flags |= O_NONBLOCK; + if( fcntl( nClient, F_SETFL, flags ) < 0) + { + throw SocketException( + "Error setting option on client socket: %s", + strerror( errno ) + ); + } + } + + return nClient; + } + + return -1; +} + diff --git a/src/serversocket.h b/src/serversocket.h new file mode 100644 index 0000000..9a26e2d --- /dev/null +++ b/src/serversocket.h @@ -0,0 +1,31 @@ +#ifndef SERVER_SOCKET_H +#define SERVER_SOCKET_H + +#include +#include "fstring.h" +#include "socket.h" + +namespace Bu +{ + /** + * + */ + class ServerSocket + { + public: + ServerSocket( int nPort, int nPoolSize=40 ); + ServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 ); + virtual ~ServerSocket(); + + int accept( int nTimeoutSec, int nTimeoutUSec ); + + private: + void startServer( struct sockaddr_in &name, int nPoolSize ); + + fd_set fdActive; + int nServer; + int nPort; + }; +} + +#endif diff --git a/src/socket.cpp b/src/socket.cpp index c4f914b..455b5c8 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -118,6 +118,7 @@ void Bu::Socket::close() //} } +/* void Bu::Socket::read() { char buffer[RBS]; @@ -132,7 +133,6 @@ void Bu::Socket::read() if( nbytes < 0 && errno != 0 && errno != EAGAIN ) { //printf("errno: %d, %s\n", errno, strerror( errno ) ); - /* Read error. */ //perror("readInput"); throw ConnectionException( excodeReadError, @@ -146,15 +146,13 @@ void Bu::Socket::read() break; nTotalRead += nbytes; sReadBuf.append( buffer, nbytes ); - /* Data read. */ if( nbytes < RBS ) { break; } - /* New test, if data is divisible by RBS bytes on some libs the - * read could block, this keeps it from happening. - */ + // New test, if data is divisible by RBS bytes on some libs the + // read could block, this keeps it from happening. { fd_set rfds; FD_ZERO(&rfds); @@ -171,13 +169,7 @@ void Bu::Socket::read() } } } - - /* - if( pProtocol != NULL && nTotalRead > 0 ) - { - pProtocol->onNewData(); - }*/ -} +}*/ size_t Bu::Socket::read( void *pBuf, size_t nBytes ) { diff --git a/src/socket.h b/src/socket.h index 3d0125d..568cad6 100644 --- a/src/socket.h +++ b/src/socket.h @@ -19,7 +19,7 @@ namespace Bu virtual ~Socket(); virtual void close(); - virtual void read(); + //virtual void read(); virtual size_t read( void *pBuf, size_t nBytes ); virtual size_t write( const void *pBuf, size_t nBytes ); @@ -33,6 +33,8 @@ namespace Bu virtual bool canWrite(); virtual bool canSeek(); + + private: int nSocket; bool bActive; diff --git a/src/tests/itoqueue1.cpp b/src/tests/itoqueue1.cpp new file mode 100644 index 0000000..f73f4d3 --- /dev/null +++ b/src/tests/itoqueue1.cpp @@ -0,0 +1,110 @@ +#include +#include "bu/ito.h" +#include "bu/itoqueue.h" + +class Reader : public Bu::Ito +{ +public: + Reader( Bu::ItoQueue &q, int id ) : + q( q ), + id( id ) + { + } + + void *run() + { + for( int i = 0; i < 10; i++ ) + { + std::string *pStr = q.dequeue( true ); + if( pStr == NULL ) + { + printf("Null received...\n"); + } + else + { + printf("[%d] read: %s\n", id, pStr->c_str() ); + delete pStr; + } + usleep( (int)(((double)rand())/((double)RAND_MAX)*2000000.0) ); + } + + return NULL; + } + +private: + Bu::ItoQueue &q; + int id; +}; + +class Writer : public Bu::Ito +{ +public: + Writer( Bu::ItoQueue &q, int id, const char *strbase ) : + q( q ), + strbase( strbase ), + id( id ) + { + } + + void *run() + { + for( int i = 0; i < 11; i++ ) + { + usleep( (int)(((double)rand())/((double)RAND_MAX)*2000000.0) ); + q.enqueue( new std::string( strbase ) ); + printf("[%d] write: %s\n", id, strbase ); + } + + return NULL; + } + +private: + Bu::ItoQueue &q; + const char *strbase; + int id; +}; + +int main() +{ + Writer *wr[5]; + Reader *rd[5]; + const char bob[][7]={ + {"Test 1"}, + {"Test 2"}, + {"Test 3"}, + {"Test 4"}, + {"Test 5"} + }; + + Bu::ItoQueue q; + + for( int j = 0; j < 5; j++ ) + { + wr[j] = new Writer( q, j, bob[j] ); + rd[j] = new Reader( q, j ); + } + + for( int j = 0; j < 5; j++ ) + { + rd[j]->start(); + } + + for( int j = 0; j < 5; j++ ) + { + wr[j]->start(); + } + + for( int j = 0; j < 5; j++ ) + { + rd[j]->join(); + } + + for( int j = 0; j < 5; j++ ) + { + delete wr[j]; + delete rd[j]; + } + + return 0; +} + diff --git a/src/tests/itoqueue2.cpp b/src/tests/itoqueue2.cpp new file mode 100644 index 0000000..f4b5e19 --- /dev/null +++ b/src/tests/itoqueue2.cpp @@ -0,0 +1,83 @@ +#include +#include "bu/ito.h" +#include "bu/itoqueue.h" +#include + +class Reader : public Bu::Ito +{ +public: + Reader( Bu::ItoQueue &q, int id ) : + q( q ), + id( id ) + { + } + + void *run() + { + for( int i = 0; i < 10; i++ ) + { + std::string *pStr = q.dequeue( 0, 500000 ); + if( pStr == NULL ) + { + printf("Null received...\n"); + i--; + } + else + { + printf("[%d] read: %s\n", id, pStr->c_str() ); + delete pStr; + } + } + + return NULL; + } + +private: + Bu::ItoQueue &q; + int id; +}; + +class Writer : public Bu::Ito +{ +public: + Writer( Bu::ItoQueue &q, int id, const char *strbase ) : + q( q ), + strbase( strbase ), + id( id ) + { + } + + void *run() + { + for( int i = 0; i < 11; i++ ) + { + sleep( 2 ); + printf("[%d] write: %s\n", id, strbase ); + q.enqueue( new std::string( strbase ) ); + } + + return NULL; + } + +private: + Bu::ItoQueue &q; + const char *strbase; + int id; +}; + +int main() +{ + printf("ETIMEDOUT: %d\n", ETIMEDOUT ); + Bu::ItoQueue q; + Writer wr( q, 0, "writer" ); + Reader rd( q, 0 ); + + rd.start(); + wr.start(); + + rd.join(); + wr.join(); + + return 0; +} + -- cgit v1.2.3 From 326125aee0b8cd807a6a1d158398078ff6bfb1e1 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Thu, 17 May 2007 21:45:50 +0000 Subject: As evidenced by my latest test, the Bu::FString copy is actually slower than the std::string copy by a rather large margin. This seems very odd, so I'm going to do a few tests, the first one is stripping out the FString shared pointer stuff and seeing if that makes an appreciable difference. --- build.conf | 3 ++ src/fstring.h | 4 +- src/old/tests/fstring.cpp | 48 ----------------- src/tests/fstring.cpp | 130 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 49 deletions(-) delete mode 100644 src/old/tests/fstring.cpp create mode 100644 src/tests/fstring.cpp (limited to 'build.conf') diff --git a/build.conf b/build.conf index c289205..35738e3 100644 --- a/build.conf +++ b/build.conf @@ -6,6 +6,9 @@ default action: check group "lnhdrs", check "libbu++.a" set "CXXFLAGS" += "-ggdb -Wall" +#set "CXXFLAGS" += "-pg" +#set "LDFLAGS" += "-pg" + filesIn("src") filter regexp("^src/(.*)\\.h$", "src/bu/{re:1}.h"): rule "hln", group "lnhdrs", diff --git a/src/fstring.h b/src/fstring.h index f738f63..43033b8 100644 --- a/src/fstring.h +++ b/src/fstring.h @@ -7,6 +7,8 @@ #include "archive.h" #include "hash.h" +#define min( a, b ) ((a @@ -131,7 +133,7 @@ namespace Bu appendChunk( pNew ); } - void append( const chr cData ) + void append( const chr &cData ) { append( &cData, 1 ); } diff --git a/src/old/tests/fstring.cpp b/src/old/tests/fstring.cpp deleted file mode 100644 index 271738c..0000000 --- a/src/old/tests/fstring.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "hash.h" -#include "fstring.h" - -FString genThing() -{ - FString bob; - bob.append("ab "); - bob += "cd "; - bob += "efg"; - - printf("---bob------\n%08X: %s\n", (unsigned int)bob.c_str(), bob.c_str() ); - return bob; -} - -void thing( FString str ) -{ - printf("Hey: %s\n", str.c_str() ); -} - -#define pem printf("---------\n%08X: %s\n%08X: %s\n", (unsigned int)str.c_str(), str.c_str(), (unsigned int)str2.c_str(), str2.c_str() ); -int main( int argc, char *argv ) -{ - FString str("th"); - - str.prepend("Hello "); - str.append("ere."); - - FString str2( str ); - pem; - str += " What's up?"; - pem; - str2 += " How are you?"; - pem; - str = str2; - pem; - - str2 = genThing(); - pem; - - str = str2; - pem; - - thing( str2 ); - thing("test."); - - printf("%d == %d\n", __calcHashCode( str ), __calcHashCode( str.c_str() ) ); -} - diff --git a/src/tests/fstring.cpp b/src/tests/fstring.cpp new file mode 100644 index 0000000..d600be6 --- /dev/null +++ b/src/tests/fstring.cpp @@ -0,0 +1,130 @@ +#include "bu/hash.h" +#include "bu/fstring.h" +#include +#include + +inline double getTime() +{ + struct timeval tv; + gettimeofday( &tv, NULL ); + return ((double)tv.tv_sec) + ((double)tv.tv_usec/1000000.0); +} + +Bu::FString genThing() +{ + Bu::FString bob; + bob.append("ab "); + bob += "cd "; + bob += "efg"; + + printf("---bob------\n%08X: %s\n", (unsigned int)bob.c_str(), bob.c_str() ); + return bob; +} + +void thing( Bu::FString str ) +{ + printf("Hey: %s\n", str.c_str() ); +} + +void copyfunc( std::string temp ) +{ + temp += "Hi"; +} + +void copyfunc( Bu::FString temp ) +{ + temp += "Hi"; +} + +void doTimings() +{ + Bu::FString fs1, fs2; + std::string ss1, ss2; + double dStart, dEnd, tfs1, tfs2, tfs3, tss1, tss2, tss3; + int nChars = 500000, nChunks=5000, nCopies=5000000, nChunkSize=1024*4; + char *buf = new char[nChunkSize]; + memset( buf, '!', nChunkSize ); + + printf("Timing Bu::FString single chars...\n"); + dStart = getTime(); + for( int j = 0; j < nChars; j++ ) fs1 += (char)('a'+(j%26)); + fs1.getStr(); + dEnd = getTime(); + tfs1 = dEnd-dStart; + + printf("Timing std::string single chars...\n"); + dStart = getTime(); + for( int j = 0; j < nChars; j++ ) ss1 += (char)('a'+(j%26)); + ss1.c_str(); + dEnd = getTime(); + tss1 = dEnd-dStart; + + printf("Timing Bu::FString %d char chunks...\n", nChunkSize); + dStart = getTime(); + for( int j = 0; j < nChunks; j++ ) fs2.append(buf, nChunkSize); + fs2.getStr(); + dEnd = getTime(); + tfs2 = dEnd-dStart; + + printf("Timing std::string %d char chunks...\n", nChunkSize); + dStart = getTime(); + for( int j = 0; j < nChunks; j++ ) ss2.append(buf, nChunkSize); + ss2.c_str(); + dEnd = getTime(); + tss2 = dEnd-dStart; + + fs2 = "Hello there."; + ss2 = "Hello there."; + printf("Timing Bu::FString copies...\n"); + dStart = getTime(); + for( int j = 0; j < nCopies; j++ ) Bu::FString stmp = fs2; + dEnd = getTime(); + tfs3 = dEnd-dStart; + + printf("Timing std::string copies...\n"); + dStart = getTime(); + for( int j = 0; j < nCopies; j++ ) std::string stpm = ss2; + dEnd = getTime(); + tss3 = dEnd-dStart; + + printf( + "Results: singles: chunks: copies:\n" + "Bu::FString %10.2f/s %10.2f/s %10.2f/s\n" + "std::string %10.2f/s %10.2f/s %10.2f/s\n", + nChars/tfs1, nChunks/tfs2, nCopies/tfs3, + nChars/tss1, nChunks/tss2, nCopies/tss3 ); + + delete[] buf; +} + +#define pem printf("---------\n%08X: %s\n%08X: %s\n", (unsigned int)str.c_str(), str.c_str(), (unsigned int)str2.c_str(), str2.c_str() ); +int main( int argc, char *argv ) +{ + Bu::FString str("th"); + + str.prepend("Hello "); + str.append("ere."); + + Bu::FString str2( str ); + pem; + str += " What's up?"; + pem; + str2 += " How are you?"; + pem; + str = str2; + pem; + + str2 = genThing(); + pem; + + str = str2; + pem; + + thing( str2 ); + thing("test."); + + printf("%d == %d\n", Bu::__calcHashCode( str ), Bu::__calcHashCode( str.c_str() ) ); + + doTimings(); +} + -- cgit v1.2.3 From 9e8a4944e50fab432012878c66e1bdac20649f76 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Thu, 7 Jun 2007 19:56:20 +0000 Subject: The Stream Filter archetecture is finished, it's actually much cooler than I had anticipated, and much cleaner. I'll have to add some documentation to it, because it's not really obvious how any of it fits together from the outset, although I have to say that the bzip2 test program is the easiest general bzip2 compression program I've ever made...it just goes :) Decompression in Bu::BZip2 isn't finished yet, but that's ok, it's coming soon. --- build.conf | 2 + src/bzip2.cpp | 123 ++++++++++++ src/bzip2.h | 35 ++++ src/entities/bu-class | 4 +- src/filter.cpp | 77 ++++++++ src/filter.h | 59 ++++++ src/fstring.h | 6 +- src/old/paramproc.cpp | 514 -------------------------------------------------- src/old/paramproc.h | 153 --------------- src/paramproc.cpp | 514 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/paramproc.h | 156 +++++++++++++++ src/stream.h | 3 + src/tests/bzip2.cpp | 23 +++ 13 files changed, 998 insertions(+), 671 deletions(-) create mode 100644 src/bzip2.cpp create mode 100644 src/bzip2.h create mode 100644 src/filter.cpp create mode 100644 src/filter.h delete mode 100644 src/old/paramproc.cpp delete mode 100644 src/old/paramproc.h create mode 100644 src/paramproc.cpp create mode 100644 src/paramproc.h create mode 100644 src/tests/bzip2.cpp (limited to 'build.conf') diff --git a/build.conf b/build.conf index 35738e3..f493d67 100644 --- a/build.conf +++ b/build.conf @@ -61,6 +61,8 @@ filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"): "tests/plugin": set "LDFLAGS" += "-ldl" +"tests/bzip2": set "LDFLAGS" += "-lbz2" + rule "exe": matches regexp("(.*)\\.o$"), aggregate toString(" "), diff --git a/src/bzip2.cpp b/src/bzip2.cpp new file mode 100644 index 0000000..b8c0f74 --- /dev/null +++ b/src/bzip2.cpp @@ -0,0 +1,123 @@ +#include "bu/bzip2.h" +#include "bu/exceptions.h" + +using namespace Bu; + +Bu::BZip2::BZip2( Bu::Stream &rNext, int nCompression ) : + Bu::Filter( rNext ), + nCompression( nCompression ) +{ + start(); +} + +Bu::BZip2::~BZip2() +{ + printf("-> Bu::BZip2::~BZip2()\n"); + stop(); +} + +void Bu::BZip2::start() +{ + printf("-> Bu::BZip2::start()\n"); + printf("Hey, it's starting...\n"); + bzState.state = NULL; + bzState.bzalloc = NULL; + bzState.bzfree = NULL; + bzState.opaque = NULL; + + nBufSize = 50000; + pBuf = new char[nBufSize]; +} + +void Bu::BZip2::stop() +{ + printf("-> Bu::BZip2::stop()\n"); + if( bzState.state ) + { + if( bReading ) + { + } + else + { + for(;;) + { + bzState.next_in = NULL; + bzState.avail_in = 0; + bzState.avail_out = nBufSize; + bzState.next_out = pBuf; + int res = BZ2_bzCompress( &bzState, BZ_FINISH ); + if( bzState.avail_out < nBufSize ) + { + rNext.write( pBuf, nBufSize-bzState.avail_out ); + } + if( res == BZ_STREAM_END ) + break; + } + BZ2_bzCompressEnd( &bzState ); + } + } +} + +void Bu::BZip2::bzError( int code ) +{ + switch( code ) + { + case BZ_OK: + return; + + case BZ_CONFIG_ERROR: + throw ExceptionBase("The bzip2 library has been miscompiled."); + + case BZ_PARAM_ERROR: + throw ExceptionBase("bzip2 parameter error."); + + case BZ_MEM_ERROR: + throw ExceptionBase("Not enough memory available for bzip2."); + } +} + +size_t Bu::BZip2::read( void *pData, size_t nBytes ) +{ + if( !bzState.state ) + { + bReading = true; + } + if( bReading == false ) + throw ExceptionBase("This bzip2 filter is in writing mode, you can't read."); + //bzState.next_in = pData; + //bzState.avail_in = nSizeIn; + + //printf("%db at [%08X] (%db)\n", bzState.avail_in, (uint32_t)bzState.next_in, bzState.total_in_lo32 ); + return 0; +} + +size_t Bu::BZip2::write( const void *pData, size_t nBytes ) +{ + if( !bzState.state ) + { + bReading = false; + BZ2_bzCompressInit( &bzState, nCompression, 0, 30 ); + } + if( bReading == true ) + throw ExceptionBase("This bzip2 filter is in reading mode, you can't write."); + + bzState.next_in = (char *)pData; + bzState.avail_in = nBytes; + for(;;) + { + bzState.avail_out = nBufSize; + bzState.next_out = pBuf; + + BZ2_bzCompress( &bzState, BZ_RUN ); + + if( bzState.avail_out < nBufSize ) + { + rNext.write( pBuf, nBufSize-bzState.avail_out ); + } + if( bzState.avail_in == 0 ) + break; + } + + return 0; +} + diff --git a/src/bzip2.h b/src/bzip2.h new file mode 100644 index 0000000..056f336 --- /dev/null +++ b/src/bzip2.h @@ -0,0 +1,35 @@ +#ifndef B_ZIP2_H +#define B_ZIP2_H + +#include +#include + +#include "bu/filter.h" + +namespace Bu +{ + /** + * + */ + class BZip2 : public Bu::Filter + { + public: + BZip2( Bu::Stream &rNext, int nCompression=9 ); + virtual ~BZip2(); + + virtual void start(); + virtual void stop(); + virtual size_t read( void *pBuf, size_t nBytes ); + virtual size_t write( const void *pBuf, size_t nBytes ); + + private: + void bzError( int code ); + bz_stream bzState; + bool bReading; + int nCompression; + char *pBuf; + uint32_t nBufSize; + }; +} + +#endif diff --git a/src/entities/bu-class b/src/entities/bu-class index 81e3d25..7b25291 100644 --- a/src/entities/bu-class +++ b/src/entities/bu-class @@ -10,7 +10,7 @@ #include <stdint.h> -{?parent:"#include \"{=parent:%tolower}.h\" +{?parent:"#include \"bu/{=parent:%tolower}.h\" "}namespace Bu { @@ -35,6 +35,8 @@ filename="{=name:%tolower}.cpp" >#include "bu/{=name:%tolower}.h" +using namespace Bu; + Bu::{=name}::{=name}() { } diff --git a/src/filter.cpp b/src/filter.cpp new file mode 100644 index 0000000..d3faa00 --- /dev/null +++ b/src/filter.cpp @@ -0,0 +1,77 @@ +#include "bu/filter.h" + +Bu::Filter::Filter( Bu::Stream &rNext ) : + rNext( rNext ) +{ +} + +Bu::Filter::~Filter() +{ + printf("-> Bu::Filter::~Filter()\n"); +} +/* +void Bu::Filter::start() +{ + printf("-> Bu::Filter::start()\n"); +} + +void Bu::Filter::stop() +{ +}*/ + +void Bu::Filter::close() +{ + stop(); + rNext.close(); +} + +long Bu::Filter::tell() +{ + return rNext.tell(); +} + +void Bu::Filter::seek( long offset ) +{ + rNext.seek( offset ); +} + +void Bu::Filter::setPos( long pos ) +{ + rNext.setPos( pos ); +} + +void Bu::Filter::setPosEnd( long pos ) +{ + rNext.setPosEnd( pos ); +} + +bool Bu::Filter::isEOS() +{ + return rNext.isEOS(); +} + +bool Bu::Filter::canRead() +{ + return rNext.canRead(); +} + +bool Bu::Filter::canWrite() +{ + return rNext.canWrite(); +} + +bool Bu::Filter::canSeek() +{ + return rNext.canSeek(); +} + +bool Bu::Filter::isBlocking() +{ + return rNext.isBlocking(); +} + +void Bu::Filter::setBlocking( bool bBlocking ) +{ + rNext.setBlocking( bBlocking ); +} + diff --git a/src/filter.h b/src/filter.h new file mode 100644 index 0000000..b068206 --- /dev/null +++ b/src/filter.h @@ -0,0 +1,59 @@ +#ifndef FILTER_H +#define FILTER_H + +#include + +#include "bu/stream.h" + +namespace Bu +{ + /** + * Data filter base class. Each data filter should contain a read and write + * section. Effectively, the write applies the filter, the read un-applies + * the filter, if possible. For example, BZip2 is a filter that compresses + * on write and decompresses on read. All bi-directional filters should + * follow: x == read( write( x ) ) (byte-for-byte comparison) + * + * Also, all returned buffers should be owned by the filter, and deleted + * when the filter is deleted. This means that the output of a read or + * write operation must be used before the next call to read or write or the + * data will be destroyed. Also, the internal buffer may be changed or + * recreated between calls, so always get a new pointer from a call to + * read or write. + * + * The close function can also return data, so make sure to check for it, + * many filters such as compression filters will buffer data until they have + * enough to create a compression block, in these cases the leftover data + * will be returned by close. + */ + class Filter : public Bu::Stream + { + public: + Filter( Bu::Stream &rNext ); + virtual ~Filter(); + + virtual void start()=0; + virtual void stop()=0; + virtual void close(); + virtual long tell(); + virtual void seek( long offset ); + virtual void setPos( long pos ); + virtual void setPosEnd( long pos ); + virtual bool isEOS(); + + virtual bool canRead(); + virtual bool canWrite(); + virtual bool canSeek(); + + virtual bool isBlocking(); + virtual void setBlocking( bool bBlocking=true ); + + protected: + Bu::Stream &rNext; + + private: + + }; +} + +#endif diff --git a/src/fstring.h b/src/fstring.h index 43033b8..d0307b5 100644 --- a/src/fstring.h +++ b/src/fstring.h @@ -3,9 +3,9 @@ #include #include -#include "archival.h" -#include "archive.h" -#include "hash.h" +#include "bu/archival.h" +#include "bu/archive.h" +#include "bu/hash.h" #define min( a, b ) ((a - -#define ptrtype( iitype, iiname ) \ - ParamProc::ParamPtr::ParamPtr( iitype *iiname ) : \ - type( vt ##iiname ) { val.iiname = iiname; } - -ParamProc::ParamPtr::ParamPtr() -{ - val.str = NULL; - type = vtunset; -} - -ptrtype( std::string, str ); -ptrtype( uint64_t, uint64 ); -ptrtype( uint32_t, uint32 ); -ptrtype( uint16_t, uint16 ); -ptrtype( uint8_t, uint8 ); -ptrtype( int64_t, int64 ); -ptrtype( int32_t, int32 ); -ptrtype( int16_t, int16 ); -ptrtype( int8_t, int8 ); -ptrtype( float, float32 ); -ptrtype( double, float64 ); -ptrtype( long double, float96 ); -ptrtype( bool, bln ); - -ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr ) -{ - val = ptr.val; - type = ptr.type; - - return *this; -} - -bool ParamProc::ParamPtr::isSet() -{ - return type != vtunset; -} - -ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( const char *str ) -{ - if( !isSet() ) return *this; - switch( type ) - { - case vtstr: - (*val.str) = str; - break; - - case vtuint64: - (*val.uint64) = strtoull( str, NULL, 10 ); - break; - - case vtuint32: - (*val.uint32) = strtoul( str, NULL, 10 ); - break; - - case vtuint16: - (*val.uint16) = (uint16_t)strtoul( str, NULL, 10 ); - break; - - case vtuint8: - (*val.uint8) = (uint8_t)strtoul( str, NULL, 10 ); - break; - - case vtint64: - (*val.int64) = strtoll( str, NULL, 10 ); - break; - - case vtint32: - (*val.int32) = strtol( str, NULL, 10 ); - break; - - case vtint16: - (*val.int16) = (int16_t)strtol( str, NULL, 10 ); - break; - - case vtint8: - (*val.int8) = (int8_t)strtol( str, NULL, 10 ); - break; - - case vtfloat32: - (*val.float32) = strtof( str, NULL ); - break; - - case vtfloat64: - (*val.float64) = strtod( str, NULL ); - break; - - case vtfloat96: - (*val.float96) = strtold( str, NULL ); - break; - - case vtbln: - if( strcasecmp("yes", str ) == 0 || - strcasecmp("true", str ) == 0 ) - { - (*val.bln) = true; - } - else - { - (*val.bln) = false; - } - break; - } - - return *this; -} - -ParamProc::ParamProc() -{ -} - -ParamProc::~ParamProc() -{ - for( std::list::iterator i = lArg.begin(); - i != lArg.end(); i++ ) - { - delete *i; - } - - for( std::list::iterator i = lBan.begin(); - i != lBan.end(); i++ ) - { - delete *i; - } - -} -/* -void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val ) -{ - printf("Calling callback...\n"); - val = "Hello there, this is set in the ParamProc"; - (this->*proc)(); -}*/ - -void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, - ParamPtr val, const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - ArgSpec *as = new ArgSpec; - if( lpWord ) - as->sWord = lpWord; - - as->cChar = cChar; - as->proc = proc; - as->val = val; - if( lpDesc ) - as->sDesc = lpDesc; - if( lpExtra ) - as->sExtra = lpExtra; - if( lpValue ) - as->sValue = lpValue; - - lArg.push_back( as ); - - if( !lBan.empty() ) - { - if( lBan.back()->pBefore == NULL ) - lBan.back()->pBefore = as; - } -} - -void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); -} - -void ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, cChar, NULL, val, lpDesc, lpExtra, lpValue ); -} - -void ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, '\0', proc, val, lpDesc, lpExtra, lpValue ); -} - -void ParamProc::addParam( const char *lpWord, Proc proc, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, '\0', proc, ParamPtr(), lpDesc, lpExtra, lpValue ); -} - -void ParamProc::addParam( const char *lpWord, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, '\0', NULL, val, lpDesc, lpExtra, lpValue ); -} - -void ParamProc::addParam( char cChar, Proc proc, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( NULL, cChar, proc, val, lpDesc, lpExtra, lpValue ); -} - -void ParamProc::addParam( char cChar, Proc proc, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( NULL, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); -} - -void ParamProc::addParam( char cChar, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( NULL, cChar, NULL, val, lpDesc, lpExtra, lpValue ); -} - -void ParamProc::process( int argc, char *argv[] ) -{ - for( int arg = 1; arg < argc; arg++ ) - { - //printf(":::%d:::%s\n", arg, argv[arg] ); - if( argv[arg][0] == '-' ) - { - if( argv[arg][1] == '-' ) - { - ArgSpec *s = checkWord( argv[arg]+2 ); - if( s ) - { - if( argv[arg][s->sWord.getLength()+2] == '=' ) - { - if( s->val.isSet() ) - { - if( s->sValue.getString() == NULL ) - { - s->val = argv[arg]+s->sWord.getLength()+3; - } - else - { - s->val = s->sValue.getString(); - } - } - if( s->proc ) - { - char **tmp = new char*[argc-arg]; - tmp[0] = argv[arg]+s->sWord.getLength()+3; - for( int k = 1; k < argc-arg; k++ ) - tmp[k] = argv[arg+k]; - int ret = (this->*s->proc)( argc-arg, tmp ); - if( ret > 0 ) - { - arg += ret-1; - } - delete tmp; - } - } - else - { - int add = 0; - if( s->val.isSet() ) - { - if( s->sValue.getString() == NULL ) - { - if( arg+1 >= argc ) - { - return; - } - s->val = argv[arg+1]; - add++; - } - else - { - s->val = s->sValue.getString(); - } - } - if( s->proc ) - { - int ret = (this->*s->proc)( - argc-arg-1, argv+arg+1 ); - - if( ret > add ) - add = 0; - else - add -= ret; - arg += ret; - } - arg += add; - } - continue; - } - else - { - unknownParam( argc-arg, argv+arg ); - } - } - else - { - for( int chr = 1; argv[arg][chr]; chr++ ) - { - ArgSpec *s = checkLetr( argv[arg][chr] ); - if( s ) - { - if( argv[arg][chr+1] != '\0' ) - { - bool bUsed = false; - if( s->val.isSet() ) - { - if( s->sValue.getString() == NULL ) - { - s->val = argv[arg]+chr+1; - bUsed = true; - } - else - { - s->val = s->sValue.getString(); - } - } - if( s->proc ) - { - char **tmp = new char*[argc-arg]; - tmp[0] = argv[arg]+chr+1; - for( int k = 1; k < argc-arg; k++ ) - tmp[k] = argv[arg+k]; - int ret = (this->*s->proc)( argc-arg, tmp ); - if( ret > 0 ) - { - arg += ret - 1; - delete tmp; - break; - } - delete tmp; - } - if( bUsed ) - { - break; - } - } - else - { - bool bUsed = false; - if( s->val.isSet() ) - { - if( s->sValue.getString() == NULL ) - { - s->val = argv[arg+1]; - bUsed = true; - } - else - { - s->val = s->sValue.getString(); - } - } - if( s->proc ) - { - int ret = (this->*s->proc)( - argc-arg-1, argv+arg+1 - ); - if( ret > 0 ) - { - arg += ret; - break; - } - } - if( bUsed ) - { - arg++; - break; - } - } - } - else - { - unknownParam( argc-arg, argv+arg ); - } - } - } - } - else - { - cmdParam( argc-arg, argv+arg ); - } - } -} - -ParamProc::ArgSpec *ParamProc::checkWord( const char *arg ) -{ - //printf("Checking \"%s\"...\n", arg ); - std::list::const_iterator i; - for( i = lArg.begin(); i != lArg.end(); i++ ) - { - if( (*i)->sWord.getString() == NULL ) - continue; - - if( !strcmp( (*i)->sWord, arg ) ) - return *i; - - if( (*i)->val.isSet() ) - { - if( !strncmp( (*i)->sWord, arg, (*i)->sWord.getLength() ) && - arg[(*i)->sWord.getLength()] == '=' ) - { - return *i; - } - } - } - - return NULL; -} - -ParamProc::ArgSpec *ParamProc::checkLetr( const char arg ) -{ - //printf("Checking \'%c\'...\n", arg ); - std::list::const_iterator i; - for( i = lArg.begin(); i != lArg.end(); i++ ) - { - if( (*i)->cChar == '\0' ) - continue; - - if( (*i)->cChar == arg ) - { - return *i; - } - } - - return NULL; -} - -int ParamProc::cmdParam( int argc, char *argv[] ) -{ - printf("Unhandled command parameter \"%s\" found!\n", argv[0] ); - return 0; -} - -int ParamProc::unknownParam( int argc, char *argv[] ) -{ - printf("Unknown parameter \"%s\" found!\n", argv[0] ); - return 0; -} - -int ParamProc::help( int argc, char *argv[] ) -{ - std::list::const_iterator b = lBan.begin(); - std::list::const_iterator i; - int len=0; - for( i = lArg.begin(); i != lArg.end(); i++ ) - { - if( len < (*i)->sWord.getLength() + (*i)->sExtra.getLength() ) - len = (*i)->sWord.getLength() + (*i)->sExtra.getLength(); - } - char fmt[10]; - sprintf( fmt, "%%-%ds ", len ); - - for( i = lArg.begin(); i != lArg.end(); i++ ) - { - if( b != lBan.end() ) - { - if( (*b)->pBefore == (*i) ) - { - printf( (*b)->sBanner.getString() ); - b++; - } - } - printf(" "); - if( (*i)->cChar ) - { - if( (*i)->sWord.getString() ) - { - printf("-%c, ", (*i)->cChar ); - } - else - { - printf("-%c ", (*i)->cChar ); - } - } - else - { - printf(" "); - } - if( (*i)->sWord.getString() ) - { - printf("--"); - std::string sTmp = (*i)->sWord.getString(); - if( (*i)->sExtra.getString() ) - sTmp += (*i)->sExtra.getString(); - printf( fmt, sTmp.c_str() ); - } - else - { - printf(" "); - printf(fmt, "" ); - } - printf("%s\n", (*i)->sDesc.getString() ); - } - if( b != lBan.end() ) - { - if( (*b)->pBefore == NULL ) - { - printf( (*b)->sBanner.getString() ); - } - } - - exit( 0 ); -} - -void ParamProc::addHelpBanner( const char *sHelpBanner ) -{ - Banner *pBan = new Banner; - pBan->sBanner = sHelpBanner; - pBan->pBefore = NULL; - lBan.push_back( pBan ); -} - diff --git a/src/old/paramproc.h b/src/old/paramproc.h deleted file mode 100644 index d857193..0000000 --- a/src/old/paramproc.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef PARAM_PROC_H -#define PARAM_PROC_H - -#include -#include -#include -#include "staticstring.h" - -class ParamProc -{ -public: - class ParamPtr - { - public: - ParamPtr(); - ParamPtr( std::string *str ); - ParamPtr( uint64_t *uint64 ); - ParamPtr( uint32_t *uint32 ); - ParamPtr( uint16_t *uint16 ); - ParamPtr( uint8_t *uint8 ); - ParamPtr( int64_t *int64 ); - ParamPtr( int32_t *int32 ); - ParamPtr( int16_t *int16 ); - ParamPtr( int8_t *int8 ); - ParamPtr( float *float32 ); - ParamPtr( double *float64 ); - ParamPtr( long double *float96 ); - ParamPtr( bool *bln ); - - enum - { - vtunset, - vtstr, - vtuint64, - vtuint32, - vtuint16, - vtuint8, - vtint64, - vtint32, - vtint16, - vtint8, - vtfloat32, - vtfloat64, - vtfloat96, - vtbln, - }; - ParamPtr &operator=( ParamPtr &ptr ); - ParamPtr &operator=( const char *str ); - - bool isSet(); - - private: - int type; - union - { - std::string *str; - uint64_t *uint64; - uint32_t *uint32; - uint16_t *uint16; - uint8_t *uint8; - int64_t *int64; - int32_t *int32; - int16_t *int16; - int8_t *int8; - float *float32; - double *float64; - long double *float96; - bool *bln; - } val; - }; - - typedef int (ParamProc::*Proc)( int, char *[] ); - - typedef struct ArgSpec - { - uint8_t nFlags; - StaticString sWord; - char cChar; - Proc proc; - ParamProc::ParamPtr val; - StaticString sExtra; - StaticString sDesc; - StaticString sValue; - } ArgSpec; - -public: - ParamProc(); - virtual ~ParamProc(); - - void addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( const char *lpWord, char cChar, Proc proc, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( const char *lpWord, char cChar, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - - void addParam( const char *lpWord, Proc proc, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( const char *lpWord, Proc proc, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( const char *lpWord, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - - void addParam( char cChar, Proc proc, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( char cChar, Proc proc, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( char cChar, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - - void process( int argc, char *argv[] ); - void addHelpBanner( const char *sHelpBanner ); - -private: - ArgSpec *checkWord( const char *arg ); - ArgSpec *checkLetr( const char arg ); - -public: - virtual int cmdParam( int argc, char *argv[] ); - virtual int unknownParam( int argc, char *argv[] ); - virtual int help( int argc, char *argv[] ); - -private: - typedef struct Banner - { - StaticString sBanner; - ArgSpec *pBefore; - } Banner; - std::list lBan; - std::list lArg; -}; - -#define mkproc( cls ) static_cast(&cls) - -#endif diff --git a/src/paramproc.cpp b/src/paramproc.cpp new file mode 100644 index 0000000..34e973e --- /dev/null +++ b/src/paramproc.cpp @@ -0,0 +1,514 @@ +#include "paramproc.h" +#include + +#define ptrtype( iitype, iiname ) \ + Bu::ParamProc::ParamPtr::ParamPtr( iitype *iiname ) : \ + type( vt ##iiname ) { val.iiname = iiname; } + +Bu::ParamProc::ParamPtr::ParamPtr() +{ + val.str = NULL; + type = vtunset; +} + +ptrtype( std::string, str ); +ptrtype( uint64_t, uint64 ); +ptrtype( uint32_t, uint32 ); +ptrtype( uint16_t, uint16 ); +ptrtype( uint8_t, uint8 ); +ptrtype( int64_t, int64 ); +ptrtype( int32_t, int32 ); +ptrtype( int16_t, int16 ); +ptrtype( int8_t, int8 ); +ptrtype( float, float32 ); +ptrtype( double, float64 ); +ptrtype( long double, float96 ); +ptrtype( bool, bln ); + +Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr ) +{ + val = ptr.val; + type = ptr.type; + + return *this; +} + +bool Bu::ParamProc::ParamPtr::isSet() +{ + return type != vtunset; +} + +Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( const char *str ) +{ + if( !isSet() ) return *this; + switch( type ) + { + case vtstr: + (*val.str) = str; + break; + + case vtuint64: + (*val.uint64) = strtoull( str, NULL, 10 ); + break; + + case vtuint32: + (*val.uint32) = strtoul( str, NULL, 10 ); + break; + + case vtuint16: + (*val.uint16) = (uint16_t)strtoul( str, NULL, 10 ); + break; + + case vtuint8: + (*val.uint8) = (uint8_t)strtoul( str, NULL, 10 ); + break; + + case vtint64: + (*val.int64) = strtoll( str, NULL, 10 ); + break; + + case vtint32: + (*val.int32) = strtol( str, NULL, 10 ); + break; + + case vtint16: + (*val.int16) = (int16_t)strtol( str, NULL, 10 ); + break; + + case vtint8: + (*val.int8) = (int8_t)strtol( str, NULL, 10 ); + break; + + case vtfloat32: + (*val.float32) = strtof( str, NULL ); + break; + + case vtfloat64: + (*val.float64) = strtod( str, NULL ); + break; + + case vtfloat96: + (*val.float96) = strtold( str, NULL ); + break; + + case vtbln: + if( strcasecmp("yes", str ) == 0 || + strcasecmp("true", str ) == 0 ) + { + (*val.bln) = true; + } + else + { + (*val.bln) = false; + } + break; + } + + return *this; +} + +Bu::ParamProc::ParamProc() +{ +} + +Bu::ParamProc::~ParamProc() +{ + for( std::list::iterator i = lArg.begin(); + i != lArg.end(); i++ ) + { + delete *i; + } + + for( std::list::iterator i = lBan.begin(); + i != lBan.end(); i++ ) + { + delete *i; + } + +} +/* +void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val ) +{ + printf("Calling callback...\n"); + val = "Hello there, this is set in the ParamProc"; + (this->*proc)(); +}*/ + +void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, + ParamPtr val, const char *lpDesc, const char *lpExtra, + const char *lpValue ) +{ + ArgSpec *as = new ArgSpec; + if( lpWord ) + as->sWord = lpWord; + + as->cChar = cChar; + as->proc = proc; + as->val = val; + if( lpDesc ) + as->sDesc = lpDesc; + if( lpExtra ) + as->sExtra = lpExtra; + if( lpValue ) + as->sValue = lpValue; + + lArg.push_back( as ); + + if( !lBan.empty() ) + { + if( lBan.back()->pBefore == NULL ) + lBan.back()->pBefore = as; + } +} + +void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, + const char *lpDesc, const char *lpExtra, + const char *lpValue ) +{ + addParam( lpWord, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); +} + +void Bu::ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val, + const char *lpDesc, const char *lpExtra, + const char *lpValue ) +{ + addParam( lpWord, cChar, NULL, val, lpDesc, lpExtra, lpValue ); +} + +void Bu::ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val, + const char *lpDesc, const char *lpExtra, + const char *lpValue ) +{ + addParam( lpWord, '\0', proc, val, lpDesc, lpExtra, lpValue ); +} + +void Bu::ParamProc::addParam( const char *lpWord, Proc proc, + const char *lpDesc, const char *lpExtra, + const char *lpValue ) +{ + addParam( lpWord, '\0', proc, ParamPtr(), lpDesc, lpExtra, lpValue ); +} + +void Bu::ParamProc::addParam( const char *lpWord, ParamPtr val, + const char *lpDesc, const char *lpExtra, + const char *lpValue ) +{ + addParam( lpWord, '\0', NULL, val, lpDesc, lpExtra, lpValue ); +} + +void Bu::ParamProc::addParam( char cChar, Proc proc, ParamPtr val, + const char *lpDesc, const char *lpExtra, + const char *lpValue ) +{ + addParam( NULL, cChar, proc, val, lpDesc, lpExtra, lpValue ); +} + +void Bu::ParamProc::addParam( char cChar, Proc proc, + const char *lpDesc, const char *lpExtra, + const char *lpValue ) +{ + addParam( NULL, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); +} + +void Bu::ParamProc::addParam( char cChar, ParamPtr val, + const char *lpDesc, const char *lpExtra, + const char *lpValue ) +{ + addParam( NULL, cChar, NULL, val, lpDesc, lpExtra, lpValue ); +} + +void Bu::ParamProc::process( int argc, char *argv[] ) +{ + for( int arg = 1; arg < argc; arg++ ) + { + //printf(":::%d:::%s\n", arg, argv[arg] ); + if( argv[arg][0] == '-' ) + { + if( argv[arg][1] == '-' ) + { + ArgSpec *s = checkWord( argv[arg]+2 ); + if( s ) + { + if( argv[arg][s->sWord.getSize()+2] == '=' ) + { + if( s->val.isSet() ) + { + if( s->sValue.getStr() == NULL ) + { + s->val = argv[arg]+s->sWord.getSize()+3; + } + else + { + s->val = s->sValue.getStr(); + } + } + if( s->proc ) + { + char **tmp = new char*[argc-arg]; + tmp[0] = argv[arg]+s->sWord.getSize()+3; + for( int k = 1; k < argc-arg; k++ ) + tmp[k] = argv[arg+k]; + int ret = (this->*s->proc)( argc-arg, tmp ); + if( ret > 0 ) + { + arg += ret-1; + } + delete tmp; + } + } + else + { + int add = 0; + if( s->val.isSet() ) + { + if( s->sValue.getStr() == NULL ) + { + if( arg+1 >= argc ) + { + return; + } + s->val = argv[arg+1]; + add++; + } + else + { + s->val = s->sValue.getStr(); + } + } + if( s->proc ) + { + int ret = (this->*s->proc)( + argc-arg-1, argv+arg+1 ); + + if( ret > add ) + add = 0; + else + add -= ret; + arg += ret; + } + arg += add; + } + continue; + } + else + { + unknownParam( argc-arg, argv+arg ); + } + } + else + { + for( int chr = 1; argv[arg][chr]; chr++ ) + { + ArgSpec *s = checkLetr( argv[arg][chr] ); + if( s ) + { + if( argv[arg][chr+1] != '\0' ) + { + bool bUsed = false; + if( s->val.isSet() ) + { + if( s->sValue.getStr() == NULL ) + { + s->val = argv[arg]+chr+1; + bUsed = true; + } + else + { + s->val = s->sValue.getStr(); + } + } + if( s->proc ) + { + char **tmp = new char*[argc-arg]; + tmp[0] = argv[arg]+chr+1; + for( int k = 1; k < argc-arg; k++ ) + tmp[k] = argv[arg+k]; + int ret = (this->*s->proc)( argc-arg, tmp ); + if( ret > 0 ) + { + arg += ret - 1; + delete tmp; + break; + } + delete tmp; + } + if( bUsed ) + { + break; + } + } + else + { + bool bUsed = false; + if( s->val.isSet() ) + { + if( s->sValue.getStr() == NULL ) + { + s->val = argv[arg+1]; + bUsed = true; + } + else + { + s->val = s->sValue.getStr(); + } + } + if( s->proc ) + { + int ret = (this->*s->proc)( + argc-arg-1, argv+arg+1 + ); + if( ret > 0 ) + { + arg += ret; + break; + } + } + if( bUsed ) + { + arg++; + break; + } + } + } + else + { + unknownParam( argc-arg, argv+arg ); + } + } + } + } + else + { + cmdParam( argc-arg, argv+arg ); + } + } +} + +Bu::ParamProc::ArgSpec *Bu::ParamProc::checkWord( const char *arg ) +{ + //printf("Checking \"%s\"...\n", arg ); + std::list::const_iterator i; + for( i = lArg.begin(); i != lArg.end(); i++ ) + { + if( (*i)->sWord.getStr() == NULL ) + continue; + + if( !strcmp( (*i)->sWord.getStr(), arg ) ) + return *i; + + if( (*i)->val.isSet() ) + { + if( !strncmp( (*i)->sWord.getStr(), arg, (*i)->sWord.getSize() ) && + arg[(*i)->sWord.getSize()] == '=' ) + { + return *i; + } + } + } + + return NULL; +} + +Bu::ParamProc::ArgSpec *Bu::ParamProc::checkLetr( const char arg ) +{ + //printf("Checking \'%c\'...\n", arg ); + std::list::const_iterator i; + for( i = lArg.begin(); i != lArg.end(); i++ ) + { + if( (*i)->cChar == '\0' ) + continue; + + if( (*i)->cChar == arg ) + { + return *i; + } + } + + return NULL; +} + +int Bu::ParamProc::cmdParam( int argc, char *argv[] ) +{ + printf("Unhandled command parameter \"%s\" found!\n", argv[0] ); + return 0; +} + +int Bu::ParamProc::unknownParam( int argc, char *argv[] ) +{ + printf("Unknown parameter \"%s\" found!\n", argv[0] ); + return 0; +} + +int Bu::ParamProc::help( int argc, char *argv[] ) +{ + std::list::const_iterator b = lBan.begin(); + std::list::const_iterator i; + int len=0; + for( i = lArg.begin(); i != lArg.end(); i++ ) + { + if( len < (*i)->sWord.getSize() + (*i)->sExtra.getSize() ) + len = (*i)->sWord.getSize() + (*i)->sExtra.getSize(); + } + char fmt[10]; + sprintf( fmt, "%%-%ds ", len ); + + for( i = lArg.begin(); i != lArg.end(); i++ ) + { + if( b != lBan.end() ) + { + if( (*b)->pBefore == (*i) ) + { + printf( (*b)->sBanner.getStr() ); + b++; + } + } + printf(" "); + if( (*i)->cChar ) + { + if( (*i)->sWord.getStr() ) + { + printf("-%c, ", (*i)->cChar ); + } + else + { + printf("-%c ", (*i)->cChar ); + } + } + else + { + printf(" "); + } + if( (*i)->sWord.getStr() ) + { + printf("--"); + std::string sTmp = (*i)->sWord.getStr(); + if( (*i)->sExtra.getStr() ) + sTmp += (*i)->sExtra.getStr(); + printf( fmt, sTmp.c_str() ); + } + else + { + printf(" "); + printf(fmt, "" ); + } + printf("%s\n", (*i)->sDesc.getStr() ); + } + if( b != lBan.end() ) + { + if( (*b)->pBefore == NULL ) + { + printf( (*b)->sBanner.getStr() ); + } + } + + exit( 0 ); +} + +void Bu::ParamProc::addHelpBanner( const char *sHelpBanner ) +{ + Banner *pBan = new Banner; + pBan->sBanner = sHelpBanner; + pBan->pBefore = NULL; + lBan.push_back( pBan ); +} + diff --git a/src/paramproc.h b/src/paramproc.h new file mode 100644 index 0000000..beee4a0 --- /dev/null +++ b/src/paramproc.h @@ -0,0 +1,156 @@ +#ifndef PARAM_PROC_H +#define PARAM_PROC_H + +#include +#include +#include +#include "bu/fstring.h" + +namespace Bu +{ + class ParamProc + { + public: + class ParamPtr + { + public: + ParamPtr(); + ParamPtr( std::string *str ); + ParamPtr( uint64_t *uint64 ); + ParamPtr( uint32_t *uint32 ); + ParamPtr( uint16_t *uint16 ); + ParamPtr( uint8_t *uint8 ); + ParamPtr( int64_t *int64 ); + ParamPtr( int32_t *int32 ); + ParamPtr( int16_t *int16 ); + ParamPtr( int8_t *int8 ); + ParamPtr( float *float32 ); + ParamPtr( double *float64 ); + ParamPtr( long double *float96 ); + ParamPtr( bool *bln ); + + enum + { + vtunset, + vtstr, + vtuint64, + vtuint32, + vtuint16, + vtuint8, + vtint64, + vtint32, + vtint16, + vtint8, + vtfloat32, + vtfloat64, + vtfloat96, + vtbln, + }; + ParamPtr &operator=( ParamPtr &ptr ); + ParamPtr &operator=( const char *str ); + + bool isSet(); + + private: + int type; + union + { + std::string *str; + uint64_t *uint64; + uint32_t *uint32; + uint16_t *uint16; + uint8_t *uint8; + int64_t *int64; + int32_t *int32; + int16_t *int16; + int8_t *int8; + float *float32; + double *float64; + long double *float96; + bool *bln; + } val; + }; + + typedef int (ParamProc::*Proc)( int, char *[] ); + + typedef struct ArgSpec + { + uint8_t nFlags; + Bu::FString sWord; + char cChar; + Proc proc; + ParamProc::ParamPtr val; + Bu::FString sExtra; + Bu::FString sDesc; + Bu::FString sValue; + } ArgSpec; + + public: + ParamProc(); + virtual ~ParamProc(); + + void addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val, + const char *lpDesc=NULL, const char *lpExtra=NULL, + const char *lpValue=NULL + ); + void addParam( const char *lpWord, char cChar, Proc proc, + const char *lpDesc=NULL, const char *lpExtra=NULL, + const char *lpValue=NULL + ); + void addParam( const char *lpWord, char cChar, ParamPtr val, + const char *lpDesc=NULL, const char *lpExtra=NULL, + const char *lpValue=NULL + ); + + void addParam( const char *lpWord, Proc proc, ParamPtr val, + const char *lpDesc=NULL, const char *lpExtra=NULL, + const char *lpValue=NULL + ); + void addParam( const char *lpWord, Proc proc, + const char *lpDesc=NULL, const char *lpExtra=NULL, + const char *lpValue=NULL + ); + void addParam( const char *lpWord, ParamPtr val, + const char *lpDesc=NULL, const char *lpExtra=NULL, + const char *lpValue=NULL + ); + + void addParam( char cChar, Proc proc, ParamPtr val, + const char *lpDesc=NULL, const char *lpExtra=NULL, + const char *lpValue=NULL + ); + void addParam( char cChar, Proc proc, + const char *lpDesc=NULL, const char *lpExtra=NULL, + const char *lpValue=NULL + ); + void addParam( char cChar, ParamPtr val, + const char *lpDesc=NULL, const char *lpExtra=NULL, + const char *lpValue=NULL + ); + + void process( int argc, char *argv[] ); + void addHelpBanner( const char *sHelpBanner ); + + private: + ArgSpec *checkWord( const char *arg ); + ArgSpec *checkLetr( const char arg ); + + public: + virtual int cmdParam( int argc, char *argv[] ); + virtual int unknownParam( int argc, char *argv[] ); + virtual int help( int argc, char *argv[] ); + + private: + typedef struct Banner + { + Bu::FString sBanner; + ArgSpec *pBefore; + } Banner; + std::list lBan; + std::list lArg; + }; +} + +#define mkproc( cls ) static_cast(&cls) + +#endif diff --git a/src/stream.h b/src/stream.h index 5f586e6..fa0a606 100644 --- a/src/stream.h +++ b/src/stream.h @@ -39,6 +39,9 @@ namespace Bu virtual bool isBlocking() = 0; virtual void setBlocking( bool bBlocking=true ) = 0; + public: // Filters + + private: }; diff --git a/src/tests/bzip2.cpp b/src/tests/bzip2.cpp new file mode 100644 index 0000000..683d3d7 --- /dev/null +++ b/src/tests/bzip2.cpp @@ -0,0 +1,23 @@ +#include "bu/bzip2.h" +#include "bu/file.h" + +int main( int argc, char *argv[] ) +{ + char buf[1024]; + size_t nRead; + + Bu::File f( "test.bz2", "wb" ); + Bu::BZip2 bz2( f ); + + Bu::File fin( argv[1], "rb"); + + for(;;) + { + nRead = fin.read( buf, 1024 ); + if( nRead > 0 ) + bz2.write( buf, nRead ); + if( fin.isEOS() ) + break; + } +} + -- cgit v1.2.3 From 5ec9a131e12d021c42b46b601f5e79502485bebb Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Wed, 27 Jun 2007 15:42:50 +0000 Subject: The MemBuf works just fine, although it still can't over-write data in the buffer. --- build.conf | 9 --------- src/membuf.cpp | 30 +++++++++++++++++++++++++++++- src/membuf.h | 7 +++++++ src/unit/entities/unit | 30 ++++++++++++++++++++++++++++++ src/unit/file.cpp | 10 ++++++++-- src/unit/hash.cpp | 4 ++-- src/unit/membuf.cpp | 37 +++++++++++++++++++++++++++++++++++++ 7 files changed, 113 insertions(+), 14 deletions(-) create mode 100644 src/unit/entities/unit create mode 100644 src/unit/membuf.cpp (limited to 'build.conf') diff --git a/build.conf b/build.conf index f493d67..d994977 100644 --- a/build.conf +++ b/build.conf @@ -41,15 +41,6 @@ filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"): ["tests/itoqueue1", "tests/itoqueue2"]: set "LDFLAGS" += "-lpthread" -directoriesIn("src/unit","unit/"): - rule "exe", - target file, - group "tests", - requires "libbu++.a", - set "CXXFLAGS" += "-Isrc", - set "LDFLAGS" += "-L. -lbu++", - input filesIn("{fulldir}") filter regexp("^.*\\.cpp$") - filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"): rule "exe", target file, diff --git a/src/membuf.cpp b/src/membuf.cpp index fdb4366..3c394b0 100644 --- a/src/membuf.cpp +++ b/src/membuf.cpp @@ -2,7 +2,8 @@ using namespace Bu; -Bu::MemBuf::MemBuf() +Bu::MemBuf::MemBuf() : + nPos( 0 ) { } @@ -16,35 +17,56 @@ void Bu::MemBuf::close() size_t Bu::MemBuf::read( void *pBuf, size_t nBytes ) { + if( (size_t)sBuf.getSize()-(size_t)nPos < nBytes ) + nBytes = sBuf.getSize()-nPos; + memcpy( pBuf, sBuf.getStr()+nPos, nBytes ); + nPos += nBytes; + + return nBytes; } size_t Bu::MemBuf::write( const void *pBuf, size_t nBytes ) { + sBuf.append( (const char *)pBuf, nBytes ); + nPos += nBytes; + return nBytes; } long Bu::MemBuf::tell() { + return nPos; } void Bu::MemBuf::seek( long offset ) { + nPos += offset; + if( nPos < 0 ) nPos = 0; + else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize(); } void Bu::MemBuf::setPos( long pos ) { + nPos = pos; + if( nPos < 0 ) nPos = 0; + else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize(); } void Bu::MemBuf::setPosEnd( long pos ) { + nPos = sBuf.getSize()-pos; + if( nPos < 0 ) nPos = 0; + else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize(); } bool Bu::MemBuf::isEOS() { + return (nPos == sBuf.getSize()); } bool Bu::MemBuf::isOpen() { + return true; } void Bu::MemBuf::flush() @@ -53,26 +75,32 @@ void Bu::MemBuf::flush() bool Bu::MemBuf::canRead() { + return !isEOS(); } bool Bu::MemBuf::canWrite() { + return isEOS(); } bool Bu::MemBuf::isReadable() { + return true; } bool Bu::MemBuf::isWritable() { + return true; } bool Bu::MemBuf::isSeekable() { + return true; } bool Bu::MemBuf::isBlocking() { + return true; } void Bu::MemBuf::setBlocking( bool bBlocking ) diff --git a/src/membuf.h b/src/membuf.h index 2cbbbdc..877b35e 100644 --- a/src/membuf.h +++ b/src/membuf.h @@ -4,6 +4,7 @@ #include #include "bu/stream.h" +#include "bu/fstring.h" namespace Bu { @@ -18,6 +19,12 @@ namespace Bu virtual void close(); virtual size_t read( void *pBuf, size_t nBytes ); + + /** + *@todo Allow writes at the current position, not just appending to + * the current buffer. This is a silly way to do it, but it covers all + * of our bases for now. + */ virtual size_t write( const void *pBuf, size_t nBytes ); virtual long tell(); virtual void seek( long offset ); diff --git a/src/unit/entities/unit b/src/unit/entities/unit new file mode 100644 index 0000000..28db45f --- /dev/null +++ b/src/unit/entities/unit @@ -0,0 +1,30 @@ + + + + #include "bu/unitsuite.h" + +class Unit : public Bu::UnitSuite +{ +public: + Unit() + { + setName("{=name}"); + addTest( Unit::test01 ); + } + + virtual ~Unit() + { + } + + void test01() + { + unitTest( 0 == 5 ); + } +}; + +int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); } + + diff --git a/src/unit/file.cpp b/src/unit/file.cpp index a45b8d7..1eaaf36 100644 --- a/src/unit/file.cpp +++ b/src/unit/file.cpp @@ -87,8 +87,14 @@ public: unitTest( sf.isEOS() == false ); try { - sf.read( buf, 5 ); - unitFailed("No exception thrown"); + if( sf.read( buf, 5 ) > 0 ) + { + unitFailed("Non-zero read result"); + } + else + { + sf.close(); + } } catch( Bu::FileException &e ) { diff --git a/src/unit/hash.cpp b/src/unit/hash.cpp index 588e687..9ea933f 100644 --- a/src/unit/hash.cpp +++ b/src/unit/hash.cpp @@ -1,6 +1,6 @@ #include "bu/fstring.h" #include "bu/hash.h" -#include "unitsuite.h" +#include "bu/unitsuite.h" #include @@ -23,7 +23,7 @@ public: { StrIntHash h; char buf[20]; - for(int i=0;i<10000;i++) + for(int i=1;i<10000;i++) { sprintf(buf,"%d",i); Bu::FString sTmp(buf); diff --git a/src/unit/membuf.cpp b/src/unit/membuf.cpp new file mode 100644 index 0000000..65ba82a --- /dev/null +++ b/src/unit/membuf.cpp @@ -0,0 +1,37 @@ +#include "bu/unitsuite.h" +#include "bu/membuf.h" + +class Unit : public Bu::UnitSuite +{ +public: + Unit() + { + setName("MemBuf"); + addTest( Unit::testWriteRead01 ); + } + + virtual ~Unit() + { + } + + void testWriteRead01() + { + Bu::MemBuf mb; + unitTest( mb.write("ab", 2 ) == 2 ); + unitTest( mb.write("cde", 3 ) == 3 ); + unitTest( mb.write("FG", 2 ) == 2 ); + + mb.setPos( 0 ); + + char buf[8]; + buf[7] = '\0'; + unitTest( mb.read( buf, 7 ) == 7 ); + unitTest( !strncmp( buf, "abcdeFG", 7 ) ); + unitTest( mb.read( buf, 7 ) == 0 ); + mb.seek( -3 ); + unitTest( mb.read( buf, 7 ) == 3 ); + unitTest( !strncmp( buf, "eFG", 3 ) ); + } +}; + +int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); } -- cgit v1.2.3