Update of /cvsroot/libfunutil/libfunutil/lib/toolbox In directory sc8-pr-cvs1:/tmp/cvs-serv12245/lib/toolbox Added Files: class_names makePrintf ns.any.h ns.argv_parser.cpp ns.argv_parser.h ns.bzstream.cpp ns.bzstream.h ns.children_holder.h ns.class_name.h ns.debuggering_macros.h ns.eprintf.h ns.file_util.cpp ns.file_util.h ns.gzstream.cpp ns.gzstream.h ns.key_value_parser.cpp ns.key_value_parser.h ns.pointer_list.h ns.property_store.cpp ns.property_store.h ns.stdstring_tokenizer.cpp ns.stdstring_tokenizer.h ns.string_tokenizer.cpp ns.string_tokenizer.h ns.string_util.cpp ns.string_util.h ns.to_string.cpp ns.to_string.h ns.type_traits.h Log Message: egg --- NEW FILE: class_names --- #!/bin/bash # sample usage: # ./class_names "std::map<std::string,std::string>" "std::pair<int,std::string>" test $1x = x && { echo "Usage: $0 class_name1 [class_name2...]" exit 1 } while test $1x != x; do cl=$1 cat <<EOF namespace { template <> struct class_name< $cl > { static const char * name() {return "$cl"; } operator const char * () const { return name(); } }; } EOF shift done --- NEW FILE: ns.any.h --- #ifndef TOOLBOX_ANY_H_INCLUDED #define TOOLBOX_ANY_H_INCLUDED 1 // License: Public Domain // Author: st...@wa... #include <string> #include <iostream> #include "to_string.h" // to/from_string namespace TOOLBOX_NAMESPACE { /** * Completely untested. * A generic 'any' type inspired by, but not based on, * boost::any. It is used to store arbitrary values which can * be "cast" (so to speak, though no casting is used) to * arbitrary types. It supports any types which are * i/ostreamable. * See the namespace-scope <code>make_any()</code> function for a conventient way * to create populated any's. * Sample usage: * <pre> * #include <any.h> * using TOOLBOX_NAMESPACE; * void any_test() * { * any a = "12.12"; * #define TESTANY(vaL,typE,defaulT) a = make_any( vaL ); std::cout << "any("<<a<<").get<"<<#typE<<">(err=["<<defaulT<<"]) = " << a.get<typE>(defaulT) << std::endl; * TESTANY(17.17,double,-1.0); * TESTANY(123.90,string,"error"); * TESTANY(123.90,double,-1.0); * TESTANY(123.90,int,-42); * TESTANY("",int,-1); * TESTANY("hi!",int,-1); * TESTANY("17.12732",double,-1.0); * TESTANY("this is a string",std::string,"error"); * TESTANY("this is a string",int,-1); * } * </pre> * will output: * <pre> * any(17.170000).get<double>(err=[-1]) = 17.17 * any(123.900000).get<string>(err=[error]) = 123.900000 * any(123.900000).get<double>(err=[-1]) = 123.9 * any(123.900000).get<int>(err=[-42]) = 123 * any().get<int>(err=[-1]) = -1 * any(hi!).get<int>(err=[-1]) = -1 * any(17.12732).get<double>(err=[-1]) = 17.1273 * any(this is a string).get<std::string>(err=[error]) = this is a string * any(this is a string).get<int>(err=[-1]) = -1 * </pre> */ class any { public: /** Creates an empty any. */ any(){} ~any() {} /** Creates any with a copy of a's value. */ any( const any & a ) : m_val(a.m_val) {} /** Copies value from rhs into this object. */ any & operator = ( const any & rhs ) { this->m_val = rhs.m_val; return *this; } // todo: template < typename ValueType > any(const ValueType & val ) : m_val(TOOLBOX_NAMESPACE::to_string( val )) {} template<typename ValueType> any & operator=(const ValueType & val ) { this->m_val = TOOLBOX_NAMESPACE::to_string( val ); return *this; } /** Returns this object's value, converted to type T, returning default_or_error_val if the value cannot be converted. T must be i/ostreamable. If a valid default_or_error_val is not immediately available, e.g., if any given integer is valid for a call to get<int>(), clients can still check for an error by checking twice against different error values: <pre> any a = make_any( 0 ); if( ( 0 == a.get<int>(0) ) && (-1 == a.get<int>(-1) ) ) error... </pre> This works because if the any can validly be converted to the first default_or_error_val then it <i>cannot</i> also be validly converted to the second default_or_error_val. Thus, if the default_or_error_val is returned on both calls the client knows that the any was not convertable to the templatized type. This property is the main reason that this class uses no exceptions. ***/ template <typename T> T get( const T & default_or_error_val = T() ) const { return TOOLBOX_NAMESPACE::from_string( this->m_val, default_or_error_val ); } /** Sets this object's value to an internal representation of val. T must be i/ostreamable. */ template <typename T> void set( const T & val ) { this->m_val = TOOLBOX_NAMESPACE::to_string( val ); } /** Sends the internal representation of A's value to the given ostream. */ friend std::ostream & operator<<( std::ostream & os, const any & A ); private: std::string m_val; }; /** Sends the internal representation of A to the given ostream. */ std::ostream & operator<<( std::ostream & os, const any & a ) { // declared in TOOLBOX_NAMESPACE::any return os << a.m_val; } /** A non-member convenience function to create an <code>any</code> representing the given value. Similar in usage to <code>std::make_pair()</code>. T must be i/ostreamble. This function should not really be a friend, but it is for documentation reasons. i.e., it's much easier to find this function if it is in the class' documentation. */ template <typename T> static any make_any( const T & value ) { return any( TOOLBOX_NAMESPACE::to_string( value ) ); } } // namespace #endif // TOOLBOX_ANY_H_INCLUDED --- NEW FILE: ns.argv_parser.cpp --- // Copyright (C) 2002, 2003 st...@wa... // Released under the See LICENSE file in this directory. #include <iostream> #include <stdio.h> // sprintf() #include "stdstring_tokenizer.h" #include "key_value_parser.h" #include "argv_parser.h" #define ARG_PREFIX "-" namespace TOOLBOX_NAMESPACE { argv_parser::argv_parser() { } argv_parser::argv_parser( int argc, char *argv[], int startAt ) { args( argc, argv, startAt ); } argv_parser::~argv_parser() { } void argv_parser::set_help( const std::string &key, const std::string &text ) { this->helpmap.set_string( key, text ); } const std::string argv_parser::getHelp( const std::string &key ) const { std::string help = helpmap.get_string( key ); return help; } std::string argv_parser::get_string( const std::string &key, const std::string & defaultVal ) const { // DO NOT call LIBE_{DEBUG,VERBOSE} from here, or you'll cause an endless loop. std::string check = property_store::get_string( key, defaultVal ); if( check != defaultVal ) return check; if( key.find( "-" ) != 0 ) // non-dashed argument { // now try -key, --key check = key; std::string foo; for( int i = 0; i < 2; i++ ) { check.insert( check.begin(), '-' ); foo = property_store::get_string( check, defaultVal ); //std::cerr << "dash test: " << check << " = " << foo << endl; if( foo != defaultVal ) return foo; } } return defaultVal; } int argv_parser::args( int argc, char *argv[], int startAt, const char *argpre ) { using namespace std; if( startAt >= argc ) return -1; if( ! argv[startAt] ) return -1; std::string argprefix = argpre ? argpre : "-"; int acount = 0; std::string v; std::string a; key_value_parser kvp; std::string nextarg; static const string numbers = "0123456789"; bool skipnext = false; char * dollarstring = (char *) malloc( 10 ); for( int i = startAt; i < argc; i++ ) { ::snprintf( dollarstring,10,"$%d", i ); this->set_string( dollarstring, argv[i] ); if( skipnext ) { skipnext = false; continue; } a = std::string( (const char *)argv[i] ); //CERR << "arg="<<a<<endl; if( a.find(argprefix)!=0 ) continue; v = std::string(); ++acount; if( kvp.parse( a ) ) // check for: --foo=bar { a = kvp.key(); v = kvp.value(); } else // else it's space-separated or a boolean flag { if( i < argc-1 ) { nextarg = std::string(argv[i+1]); if( nextarg == "-" ) { // workaround for things like: myapp --infile - v = "-"; skipnext = true; } else if( nextarg.find(argprefix) == 0 ) { if( nextarg.find_first_of( numbers ) == 1 ) { // let's assume it's a negative number, not a flag // todo: actual atol() or atod() check // Note that this logic means that numbers as flags is not supported. :/ skipnext = true; v = nextarg; } else { // nextarg is argprefix'd, so treat this as a boolean flag v = "true"; } } else { // it was space-separated: --foo bar v = nextarg; skipnext = true; } } else { v = "true"; // the final item is an argument, toggling it to true. } } this->set( a, v ); //CERR << "["<<a<<"] = ["<<v<<"]"<<endl; } free( dollarstring ); return acount; } int argv_parser::args( std::string args, std::string separators ) { // if( args.empty() || args.find( "#" ) == 0 ) return 0; // arguable if( args.empty() ) return 0; stdstring_tokenizer toker; static const int maxargs = 256; char *cargs[maxargs]; // max number of arguments. This size is completely arbitrarily chosen. int count = 0; toker.tokenize( args, separators ); int argbufsize = 1024; while( toker.has_tokens() && count < maxargs - 1) { cargs[count] = (char *)malloc( argbufsize ); // if this isn't enough... there's a problem. strncpy( cargs[count], toker.next_token().c_str(), argbufsize ); // CERR << "parse(): token= [" << cargs[count] << "]" << endl; ++count; } cargs[count] = 0; int ret = count ? this->args( count, cargs, 0, 0 ) : 0; for( int i = 0; i < count; i++ ) free( cargs[i] ); return ret; } const std::string argv_parser::dump_help( bool scv /* show current values? */ ) const { property_store::const_iterator iter = this->helpmap.begin(); std::string outs; std::string key, val, realkey; // outs += "argument_name:"; // if( scv ) outs += " [current value]"; // outs += "\n\thelp text for argument.\n\n"; while( iter != this->helpmap.end() ) { key = (*iter).first; outs += key; outs += ':'; if( scv ) { val = this->get_string( key ); // this handles dashes for us, (*iter).second does not. if( ! val.empty() ) { outs += " ["; outs += val; outs += "]"; } } outs += "\n\t"; outs += this->getHelp( key ); outs += '\n'; ++iter; } outs += "\nAll arguments must start with either - or --, like -help or --help.\n"; outs += "Arguments and their values may optionally be separated by '=', and a '=' is required if the value starts with a '-'.\n"; return outs; } argv_parser & // static argv_parser::args( int argc, char *argv[] ) { argv_parser::args().args( argc, argv, 0 ); return argv_parser::args(); } argv_parser & // static argv_parser::args() { static argv_parser sharedargs; return sharedargs; } bool argv_parser::is_help_set() { return this->is_set( "help" ) || this->is_set( "-?" ) ; } bool argv_parser::is_set( const std::string &key ) const { //std::cout << "is_set( "<<key<<")???"<<endl; if( property_store::is_set( key ) ) return true; if( key.find( "-" ) != 0 ) // non-dashed argument { if( property_store::is_set( string("--")+key ) ) return true; if( property_store::is_set( string("-")+key ) ) return true; } return false; } } // namespace TOOLBOX_NAMESPACE --- NEW FILE: ns.argv_parser.h --- #ifndef ARGV_PARSER_H #define ARGV_PARSER_H 1 // Author: st...@wa... // License: Public Domain #include "property_store.h" namespace TOOLBOX_NAMESPACE { /** argv_parser is an object for parsing command line options. It exists in the s11n source tree only to ease development of test apps, and should not be considered to be part of the core library. Use it like this: <pre> #include <iostream> #include "argv_parser.h" #define VERBOSE if( opts.get( "verbose", false ) ) cerr int main( int argc, char **argv ) { argv_parser & opts = argv_parser::args( argc, argv ); opts.set( "dosomething", ! opts.get_bool( "donothing", false ) ); if( ! opts.get( "dosomething", true ) ) { exit( 0 )); } int myint = opts.get( "width", 20 ); double myangle = opts.get( "angle", 0.0 ); VERBOSE << "This is a verbose message." << endl; return opts.get( "errorcode", 0 ); } </pre> (that code's just off the top of my head - it may not compile as-is.) Note that client code outside of main can then get access to the args via the static function args(): <pre> argv_parser & opts = argv_parser::args(); </pre> See the property_store object's API for a full list of accessor functions. Supported command-line formats: <pre> -foo bar [that is, -foo == "bar"] is the same as: [--foo bar] [-foo=bar] [--foo=bar] -foo -bar false [-foo == true, -bar == false] -foo -bar=false [same] --double-dashed "some string value" --double-dashed="some string value" [same as previous line] </pre> Whether you use single or double dashes is irrelevant, but you must call get() with the same key as was actually passed on the command-line, like so: int width = opts.getInt( "-width", opts.getInt( "--width", 42 ) ); will check for -width first, then --width, defaulting to 42. Alternately, if you use this form: opts.get_string( "foo" ); // WITHOUT a dash the following options are searched: <ol> <li>foo <li>-foo <li>--foo </ol> so the above call may actually result in getting the value from -foo or --foo. This is a potential logic problem if your application uses two semantically-different, like-named arguments like -force and --force. In this case a call to get( "force" ) would find -force and not --force. Use get( "-force" ) or get("--force") to avoid this ambiguity. The dashed versions of an argument are only sought after if get() is called without a dash before the key. These sample dash-searching rules apply to is_set(). A note to Qt users: call args() on this object before calling QApplication a(argc, argv ), or QApplication will steal any argument called -name (and possibly others), removing it from argv. i.e., if you do not call args() on this object first, QApplication may steal arguments so you'll never see them. Been there, done that. Known Bugs and/or gotchyas: Negative numbers: <pre> --boolflag -123=something </pre> will be parsed as: <pre> [--boolflag == true] [-123=something] </pre> Search the .cpp file for 'negative' and you'll find where this bug lives. Since numeric arguments are so rare this is not such a big deal, i think. i can think of only a few real-world examples which use args like -1: ssh, [GNU] xargs, head, tail, lpr, ... okay, maybe they aren't so uncommon :/ Along those same lines: <pre> --bool -234 --foobar </pre> will be parsed as: <pre> [--bool == -234] [--foobar == true] </pre> Which i consider to be correct for most cases. If you want to set --bool to a negative number use: --bool=-123 If you want to force a boolean value in this case: <pre> --bool=true -234 546 </pre> parses as: <pre> --bool=true -234=456 </pre> i hate the inconsistency this adds, though. :/ */ class argv_parser : public property_store { public: /** Creates a new parser using the given arguments array and arg count. */ argv_parser( int argc, char *argv[], int startAt=0 ); argv_parser(); virtual ~argv_parser(); /** args( int, char * ) should be called once from your main() if you want clients to be able to use args() to get at them. */ static argv_parser & args( int argc, char *argv[] ); /** Returns the object containing the arguments supplied to args(int,char**). */ static argv_parser & args(); /** get/set_help() text for a given key. */ virtual void set_help( const std::string &key, const std::string &text ); /** Returns the help text associated with key. */ virtual const std::string getHelp( const std::string &key ) const; /** Re-implemented to check keys -FOO and --FOO if key FOO is not found. */ virtual bool is_set( const std::string &key ) const; /** get_string() is overridden to add a special case to all get() calls made via the property_store API: if a get() function is called with a key which does not start with a dash (-) character and they key cannot be found in our list then -key and --key will be tried. This means that, assuming the above sample code is in place, the following would work: <pre> ~/ > myapp --foo=17.34 ... double d = opts.getDouble( "foo", 0.0 ); // d == 17.34 </pre> As will this: <pre> opts.set( "--mykey", "myvalue" ); ... cerr << "mykey="<< opts.get_string( "mykey" ) << endl; </pre> Note, however, that command-line arguments passed without a leading dash are not treated as arguments, and will not be inside this object if the command-line arguments are passed in via args(). Additionally, it is important to note that if key is passed in with a leading "-" then the additional "dash checking" is NOT done. That is, if you call: <pre> opts.get_string( "-d", 0.0 ); </pre> then ONLY the entry -d will match, and not --d. */ virtual std::string get_string( const std::string &key, const std::string & defaultVal = std::string() ) const; /** * Makes a half-hearted attempt to parse out any args (begining with "-"). * Any args without values passed after them are assigned the value true. * Sample valid command lines: * <pre> * foo --a --b foo --c bar --f * (--a and --f == true, --b == "foo" and --c == "bar") * foo --a eat --b this --c "you lazy bum" * (--a==eat, --b==this, --c=="you lazy bum") * foo --a=b --c d * (--a == b, --c == d) </pre> * * These are identical for purposes of get( "c" ): <pre> * [... -c=-1.0 ...] [... -c -1.0 ...] [... --c 1.0 ...] [... --c=1.0 ...] </pre> * * * To get the values, call the property_store API functions like: <pre> * int foo = parser.getInt( "--i" ); // getInt("i") now works for -i or --i :) * bool bar = parser.get_bool( "--b" ); // or get_bool( "b") for -b or --b </pre> * 'startat' says which element in argv[] to start with. * * If argpre = 0 then it uses the default argument prefix (defaults to "-"). * If it is >0 then that is used as a char * prefix * for all arguments. * * This function also stores all processed values in a way familiar to bash and perl users: * $0 = the first argument, * $1 = the second arg * etc. * Thus given: <pre> * ./foo --arg1 val1 --arg2=foo </pre> * We have: <pre> * myargs["$1"] == "--arg1" * myargs["$3"] == "--arg2=foo" (it is arguably useful to split these, but then usage would be * inconsistent with bash/perl. However, as it is now it is inconsistent * with the results of "--arg2 foo" :/) </pre> * Note that the values are added to this object (or overwrite existing entries), and the list * is not cleared by this function. */ virtual int args( int argc, char *argv[], int startAt, const char *argpre = "-" ); /** * Similar to parse( int... ) except that this one reads a whole line of options, parses that into * an array, then passes it to parse(...). Note that this _may_ (but should not, ideally) behave slightly * differently from arguments passed to the other form, which typically come in as command-line args * (parsed by your shell). This functions uses a stdstring_tokenizer to do it's parsing, so * any differences in behaviour should be resolved there. i am not aware of any differences. */ virtual int args( std::string args, std::string separators = " " ); /** Creates a "usage"-like string for this object containing all keys for which set_help() has been called. If showcurrentvals is true then the current values are also added to th string, otherwise they are left out. Note that the order of the dumped help text/keys is alphabetic (because that's how the container object stores them). TODO: maintain the order of args, using the order from set_help(). Sample: <pre> in main() do: argv_parser & args = argv_parser::args( argc, argv ); if( args.is_hel_set() ) { // triggers on --help, -help, -? or --? cerr << args.dump_help(); exit( 0 ); // some apps exit with a non-zero for help, some don't. } </pre> */ virtual const std::string dump_help( bool showcurrentvals = true ) const; /** Returns true if -help --help, -? or --? is set. */ virtual bool is_help_set(); private: property_store helpmap; }; }; // namespace TOOLBOX_NAMESPACE #endif // ARGV_PARSER_H --- NEW FILE: ns.bzstream.cpp --- // ============================================================================ // bzstream, C++ iostream classes wrapping the zlib compression library. // Copyright (C) 2001 Deepak Bandyopadhyay, Lutz Kettner // Copyright (C) 2003 stephan beal <st...@s1...> // This code is basically a copy/paste of gzstream, adapted for libbz2 // by stephan (2 Oct 2003) // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ============================================================================ // // File : bzstream.cpp // Revision : $Revision: 1.1 $ // Revision_date : $Date: 2003/11/17 19:22:02 $ // Author(s) : Deepak Bandyopadhyay, Lutz Kettner // // Standard streambuf implementation following Nicolai Josuttis, "The // Standard C++ Library". // ============================================================================ #include "bzstream.h" #include <iostream> #include <string.h> // for memcpy #ifdef ZSTREAM_NAMESPACE namespace ZSTREAM_NAMESPACE { #endif // ---------------------------------------------------------------------------- // Internal classes to implement bzstream. See header file for user classes. // ---------------------------------------------------------------------------- // -------------------------------------- // class bzstreambuf: // -------------------------------------- bzstreambuf *bzstreambuf::open( const char *name, int open_mode ) { if ( is_open( ) ) return ( bzstreambuf * ) 0; mode = open_mode; // no append nor read/write mode if ( ( mode & std::ios::ate ) || ( mode & std::ios::app ) || ( ( mode & std::ios::in ) && ( mode & std::ios::out ) ) ) return ( bzstreambuf * ) 0; char fmode[10]; for( unsigned int i = 0; i < sizeof(fmode); i++ ) fmode[i] = '\0'; char *fmodeptr = fmode; if ( mode & std::ios::in ) *fmodeptr++ = 'r'; else if ( mode & std::ios::out ) { *fmodeptr++ = 'w'; if( this->zlevel() >= 0 && this->zlevel() <= 9 ) { *fmodeptr++ = (char)48 + this->zlevel(); // '0' - '9' } } *fmodeptr++ = 'b'; *fmodeptr = '\0'; file = BZ2_bzopen( name, fmode ); if ( file == 0 ) return ( bzstreambuf * ) 0; opened = 1; return this; } bzstreambuf *bzstreambuf::close( ) { if ( is_open( ) ) { sync( ); opened = 0; BZ2_bzclose( file ); int errnum; BZ2_bzerror( file, &errnum ); if( BZ_OK == errnum ) return this; } return ( bzstreambuf * ) 0; } int bzstreambuf::underflow( ) { // used for input buffer only if ( gptr( ) && ( gptr( ) < egptr( ) ) ) return *reinterpret_cast < unsigned char *>( gptr( ) ); if ( !( mode & std::ios::in ) || !opened ) return EOF; // Josuttis' implementation of inbuf int n_putback = gptr( ) - eback( ); if ( n_putback > 4 ) n_putback = 4; memcpy( buffer + ( 4 - n_putback ), gptr( ) - n_putback, n_putback ); int num = BZ2_bzread( file, buffer + 4, bufferSize - 4 ); if ( num <= 0 ) // ERROR or EOF return EOF; // reset buffer pointers setg( buffer + ( 4 - n_putback ), // beginning of putback area buffer + 4, // read position buffer + 4 + num ); // end of buffer // return next character return *reinterpret_cast < unsigned char *>( gptr( ) ); } int bzstreambuf::flush_buffer( ) { // Separate the writing of the buffer from overflow() and // sync() operation. int w = pptr( ) - pbase( ); if ( BZ2_bzwrite( file, pbase( ), w ) != w ) return EOF; pbump( -w ); return w; } int bzstreambuf::overflow( int c ) { // used for output buffer only if ( !( mode & std::ios::out ) || !opened ) return EOF; if ( c != EOF ) { *pptr( ) = c; pbump( 1 ); } if ( flush_buffer( ) == EOF ) return EOF; return c; } int bzstreambuf::sync( ) { // Changed to use flush_buffer() instead of overflow( EOF) // which caused improper behavior with std::endl and flush(), // bug reported by Vincent Ricard. if ( pptr( ) && pptr( ) > pbase( ) ) { if ( flush_buffer( ) == EOF ) return -1; } return 0; } // -------------------------------------- // class bzstreambase: // -------------------------------------- bzstreambase::bzstreambase( const char *name, int mode ) { init( &buf ); open( name, mode ); } bzstreambase::~bzstreambase( ) { buf.close( ); } void bzstreambase::open( const char *name, int open_mode ) { if ( !buf.open( name, open_mode ) ) clear( rdstate( ) | std::ios::badbit ); } void bzstreambase::close( ) { if ( buf.is_open( ) ) if ( !buf.close( ) ) clear( rdstate( ) | std::ios::badbit ); } #ifdef ZSTREAM_NAMESPACE } // namespace ZSTREAM_NAMESPACE #endif // ============================================================================ // EOF // --- NEW FILE: ns.bzstream.h --- // ============================================================================ // bzstream, C++ iostream classes wrapping the bz2lib compression library. // Copyright (C) 2001 Deepak Bandyopadhyay, Lutz Kettner // Copyright (C) 2003 stephan beal <st...@s1...> // // This code is basically a copy/paste of gzstream, adapted for libbz2 // by st...@s1... (2 Oct 2003) // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ============================================================================ // // File : bzstream.h // Revision : $Revision: 1.1 $ // Revision_date : $Date: 2003/11/17 19:22:02 $ // Author(s) : Deepak Bandyopadhyay, Lutz Kettner // // Standard streambuf implementation following Nicolai Josuttis, "The // Standard C++ Library". // ============================================================================ // Changes by st...@s1...: // October, 2003: // - added zlevel() to gzstreambase and gzstreambuf. Only works for ostreams. // - replaced gzip code with bzip code. #ifndef BZSTREAM_H_INCLUDED #define BZSTREAM_H_INCLUDED 1 // standard C++ with new header file names and std:: namespace #include <iostream> #include <fstream> #include <bzlib.h> // libbz2 header #ifndef ZSTREAM_NAMESPACE #define ZSTREAM_NAMESPACE TOOLBOX_NAMESPACE #endif #ifdef ZSTREAM_NAMESPACE namespace ZSTREAM_NAMESPACE { #endif // ---------------------------------------------------------------------------- // Internal classes to implement bzstream. See below for user classes. // ---------------------------------------------------------------------------- class bzstreambuf:public std::streambuf { private: static const int bufferSize = 47 + 256; // size of data buff // totals 512 bytes under g++ for ibzstream at the end. BZFILE * file; // file handle for compressed file char buffer[bufferSize]; // data buffer char opened; // open/close state of stream int mode; // I/O mode int flush_buffer( ); public: bzstreambuf( ):opened( 0 ), m_zlevel(-1) { setp( buffer, buffer + ( bufferSize - 1 ) ); setg( buffer + 4, // beginning of putback area buffer + 4, // read position buffer + 4 ); // end position // ASSERT: both input & output capabilities will not be used together } int is_open( ) { return opened; } bzstreambuf *open( const char *name, int open_mode ); bzstreambuf *close( ); ~bzstreambuf( ) { close( ); } virtual int overflow( int c = EOF ); virtual int underflow( ); virtual int sync( ); /** Defines the compression level, 0 - 9. A value of -1 means use the system-wide zlib default (normally 3). */ void zlevel( int z ) { this->m_zlevel = ( z<0 ? -1 : (z>9?9:z) ) ; } /** Returns the compression level for this stream. */ int zlevel() const { return this->m_zlevel; } private: int m_zlevel; }; /** Base stream class inherited by obzstream/igzstream. Any given instance may not be used for both input and output. Uses gzlib compression, and is compatible with files compressed using bzip2, or any number of other tools which support bz2lib. */ class bzstreambase:virtual public std::ios { private: int m_zlevel; protected: bzstreambuf buf; public: bzstreambase( ) { init( &buf ); } bzstreambase( const char *name, int open_mode ); ~bzstreambase( ); void open( const char *name, int open_mode ); void close( ); void zlevel( int z ) { buf.zlevel(z); } int zlevel() const { return buf.zlevel(); } bzstreambuf *rdbuf( ) { return &buf; } }; /** An input stream which decompresses it's input. Used identically to a std::ifstream. <pre> igzstream ifs( "myfile.bz2" ); </pre> */ class ibzstream:public bzstreambase, public std::istream { public: ibzstream( ):std::istream( &buf ) { } ibzstream( const char *name, int open_mode = std::ios::in ):bzstreambase( name, open_mode ), std::istream( &buf ) { } bzstreambuf *rdbuf( ) { return bzstreambase::rdbuf( ); } void open( const char *name, int open_mode = std::ios::in ) { bzstreambase::open( name, open_mode ); } }; /** An output stream which compresses it's output. Used identically to a std::ofstream: <pre> ogzstream of( "myfile.bz2" ); of << "hello, world!" << std::endl; </pre> */ class obzstream:public bzstreambase, public std::ostream { public: obzstream( ):std::ostream( &buf ) { } obzstream( const char *name, int mode = std::ios::out ):bzstreambase( name, mode ), std::ostream( &buf ) { } bzstreambuf *rdbuf( ) { return bzstreambase::rdbuf( ); } void open( const char *name, int open_mode = std::ios::out ) { bzstreambase::open( name, open_mode ); } }; #ifdef ZSTREAM_NAMESPACE } // namespace ZSTREAM_NAMESPACE #endif #endif // BZSTREAM_H_INCLUDED // ============================================================================ // EOF // --- NEW FILE: ns.children_holder.h --- // Author: stephan beal <st...@s1...> // License: Public Domain #ifndef CHILDRENHOLDER_H_INCLUDED #define CHILDRENHOLDER_H_INCLUDED 1 #include <string> #include <list> #include <map> #include <vector> //#include <deque> // causes crashes in some cases where vector does not :/ #ifndef TYPENAME #define TYPENAME typename // gcc 3.x handles typenames "properly" and gcc 2.95.3 does not, so we must do -DTYPENAME= // for gcc 2.95.3. #endif namespace TOOLBOX_NAMESPACE { /** EXPERIMENTAL! children_holder is an experimental object for creating pointer containers for arbitrary child types. The idea is that many objects i create have a heirarchical structure, and i'm looking for a generic way to code this pattern. The interface should allow any given class, including non-modifiable 3rd-party classes, to have any number of child types. This code does no automatic clean-up of children. Client code may free all child pointers by calling cleanup_parent(), and subclasses or proxies of this object should call that in their dtor. */ template < class PType, class CType > class children_holder { public: /** The type of this object's parents in parent-child relationships. */ typedef PType parent_type; /** The type of this object's children in parent-child relationships. */ typedef CType child_type; /** The container type used to store the lists of children. */ typedef std::vector < child_type * >list_type; /** A shortcut typedef to help ease the implementation code for this class. */ typedef children_holder < parent_type, child_type > ThisType; /** iterator which can be dereferenced to a (child_type *). */ typedef typename list_type::iterator iterator; /** iterator which can be dereferenced to a (const child_type *). */ typedef typename list_type::const_iterator const_iterator; /** Returns the child list for the given parent object. If creationPolicy is non-zero then this function will create the child list if it does not yet exist (in that case, this function will never return NULL except on an out-of-memory error). The caller takes ownership of the returned pointer. All children in the list can be deleted at once by calling cleanup_parent( parent ). Different calls to this function will always return the same list (or the same NULL, depending on creationPolicy ;) until either unmap_parent() or cleanup_parent() are called, in which case further calls to this function may return a different pointer the next time it is called. */ static ThisType::list_type * child_list( const ThisType::parent_type * parent, int creationPolicy = 0 ) { if ( !parent ) return NULL; static ThisType::map_type & cmap = parentChildMap(); typename map_type::const_iterator it = cmap.find( parent ); if ( cmap.end() != it ) return ( *it ).second; if ( 0 == creationPolicy ) return NULL; list_type *cl = new list_type(); cmap[parent] = cl; return cl; } /** Removes parent from this object's internal map. This only removes the pointer to the parent's child list and the mapping which binds the parent to the children, but does not delete() anything. Returns true if it unmaps the parent, else false. It will only fail if it doesn't have an entry for parent. This is more of a maintenance detail than anything else. */ static bool unmap_parent( const ThisType::parent_type * parent ) { if ( !parent ) return false; static ThisType::map_type & cmap = parentChildMap(); TYPENAME ThisType::map_type::iterator it = cmap.find( parent ); if ( it == cmap.end() ) return false; cmap.erase( parent ); return true; } /** Simlar as unmap_parent(), but also deletes the children in the list and then deletes the list. Subclasses or proxies of this class should call this function from their dtor, in order to avoid leaving any dangling pointers in this class' internal data. */ static bool cleanup_parent( const ThisType::parent_type * parent ) { if ( !parent ) return false; static ThisType::map_type & cmap = parentChildMap(); TYPENAME ThisType::map_type::iterator it = cmap.find( parent ); if ( it == cmap.end() ) { // we were probably just never registed because children() was never called. return false; } TYPENAME ThisType::list_type * li = ( *it ).second; if ( !unmap_parent( parent ) ) { return false; } TYPENAME ThisType::list_type::iterator vit; TYPENAME ThisType::child_type * child = 0; for ( vit = li->begin(); li->begin() != li->end() ) { child = ( *vit ); li->erase( vit ); delete( child ); child = 0; } delete( li ); return true; } private: typedef std::map < const ThisType::parent_type *, ThisType::list_type * > map_type; /** i hate working with static objects in template classes (for syntax reasons), and parentChildMap() is a helper to avoid that. */ static map_type & parentChildMap() { static map_type meyers; return meyers; } }; }; // namespace TOOLBOX_NAMESPACE #endif // CHILDRENHOLDER_H_INCLUDED --- NEW FILE: ns.class_name.h --- #ifndef CLASS_NAME_H_INCLUDED #define CLASS_NAME_H_INCLUDED 1 #include <cassert> namespace { // ns is not strictly necessary: works in global-scope as well. /** A utility class to provide human-usable class names, available at runtime. It MUST be specialized to work. Call one of these macros: <pre> CLASS_NAME(Type) CLASS_NAME_ALIAS(Type,AliasForType) </pre> from a class' header file (not an impl file, for complex linking reasons). It may only be called one time per Type per compilation unit, or you will get specialization collisions at compile time. Caveats: - template types with commas in the names will break the macro and... - typedef'd names will get their typedef'd name registered, not their real name. Maybe a feature, maybe not. To get proper names for such cases you must hand-specialize this class. See the macros for a sample implementation, or the class_names shell script which should have come with this class. */ template <class T> struct class_name { /** returns the class name for class T. */ static const char * name() { assert( 0 /* this class_name<> is unspecialized! */ ); return "error::class_name<unspecialized>"; } /** returns the class name for class T. */ operator const char * () const { return name(); } }; } // namespace /** Creates a class_name<> specialization for Type, using the class name Alias. */ #define CLASS_NAME_ALIAS(Type,Alias) \ namespace { \ template <> struct class_name< Type > {\ static const char * name() {return # Alias; }\ operator const char * () const { return name(); }\ };} #define CLASS_NAME(Type) CLASS_NAME_ALIAS(Type,Type) #endif // CLASS_NAME_H_INCLUDED --- NEW FILE: ns.debuggering_macros.h --- #ifndef DEBUGGERING_MACROS_H #define DEBUGGERING_MACROS_H 1 // CERR is a drop-in replacement for std::cerr, but slightly more // decorative. #ifndef CERR #define CERR std::cerr << __FILE__ << ":" << std::dec << __LINE__ << " : " #define CERRL(A) CERR << A << std::endl; #endif #ifndef COUT #define COUT std::cout << __FILE__ << ":" << std::dec << __LINE__ << " : " #define COUTL(A) COUT << A << std::endl; #endif #endif // DEBUGGERING_MACROS_H --- NEW FILE: ns.eprintf.h --- #ifndef EPRINTF_H_INCLUDED #define EPRINTF_H_INCLUDED 1 // License: Public Domain // Author: st...@wa... #include <iostream> #include <sstream> namespace TOOLBOX_NAMESPACE { /** The eprintf()-related functions: (Note: these functions have an "e" prefix ONLY because gcc 2.95.x warns about incorrect number of printf args, even when TOOLBOX_NAMESPACE::printf() is specified :/. Since i needed a prefix, and 'elib' was the library this code originated from, 'e' was the choice.) These functions are auto-generated, and they all follow the pattern set here: template <typename T0> static void esprintf( std::ostream & stream, T0 v0 ); template <typename T0> static void eprintf( T0 v0 ); template <typename T0> static std::string efstring( T0 v0 ); The same functions, taking up to 20 template parameters, are included via eprintf_impl.h (which is generated by makeEPrintf). (The exact number of parameters may be different: it's set in the Makefile.) Sample usage: <pre> cout << TOOLBOX_NAMESPACE::efstring("The int is ",42,". The double is ",42.42,".") << endl; TOOLBOX_NAMESPACE::esprintf(std::cout, "The int is ",42,". The double is ",42.42,".\n"); TOOLBOX_NAMESPACE::eprintf("Simply goes to cout.\n"); </pre> (Note the addition of a \n (or endl) to the string when using the stream-accepting variants.) Design note: the auto-generated sprintf() is more code-repetative than necessary, rather than recursive, to keep down the number of template instantiations. Consider: sprintf(cout,1,2,3,4,5,6,7,8,9,10); If that was implemented recursively, we would have 10 template instantiations (one for each number of arguments, not including the stream). The current impl will only generate 1 tmpl instantiation for that call. For maintenance reasons, printf() and fstring() are implemented in terms of sprintf(), so each unique-parm-count call to printf() or fstring() will incur 2 template instantiations: one for the function and one for the sprintf() it uses. They /could/ be implemented exactly like sprintf(), sparing a function call and a template instantiation, and this may change at some point (if i need a performance scapegoat). i tend to make lots of various printf() calls, but don't call them terribly many times, so i'm not too worried about it at this point. Note that these functions provide no additional functionality whatsoever over using standard streams, except /perhaps/ a nicer-looking calling convention. But, to be frank, i was too stoned to realize that until after the code was complete. ;) (Well, i /do/ get some use out of efstring(), anyway.) */ template <typename T0> static void esprintf( std::ostream & stream, const T0 & v0 ) { stream << v0; }; template <typename T0> static void eprintf( const T0 & v0 ) { TOOLBOX_NAMESPACE::esprintf( std::cout, v0 ); }; template <typename T0> static std::string efstring( const T0 & v0 ) { std::ostringstream stream; TOOLBOX_NAMESPACE::esprintf( stream, v0 ); return stream.str(); }; #include "eprintf_impl.h" }; // namespace TOOLBOX_NAMESPACE #endif // EPRINTF_H_INCLUDED --- NEW FILE: ns.file_util.cpp --- #include <iostream> #include <fstream> #include <map> #include <stdio.h> //fopen()/fread() #include "file_util.h" #include "debuggering_macros.h" // COUT macro #if HAVE_CONFIG_H # include "config.h" #endif #include <fstream> #if HAVE_ZLIB # include "gzstream.h" #endif #if HAVE_BZLIB # include "bzstream.h" #endif namespace TOOLBOX_NAMESPACE { static int m_comp_policy = TOOLBOX_NAMESPACE::NoCompression; void compression_policy( CompressionPolicy c ) { //CERR << "compression_policy = " << c << std::endl; m_comp_policy = c; } int compression_policy() { return m_comp_policy; } std::istream * get_istream( const std::string & filename ) { // if( "-" == filename ) return &std::cin; // i'd like // that, but clients will then delete it :/. One option // might be via tie(), but i have no experience with it. //CERR << "get_istream("<<filename<<")"<<std::endl; enum FTypes { Unknown, GZip, BZip }; std::ifstream check( filename.c_str() ); if( ! check.good() ) return NULL; FILE * inf = fopen( filename.c_str(), "rb" ); if( ! inf ) { CERR << "fopen("<<filename<<") failed!" << std::endl; return NULL; } unsigned char buff[4]; fread( buff, sizeof(buff), 1, inf ); fclose( inf ); #if HAVE_BZLIB // bzip=5a42 3968 (dec: 90 66 57 104) ascii: ZB9h if( 'B' == buff[0] && 'Z' == buff[1] ) { //COUT << "bzip!"<<std::endl; return new TOOLBOX_NAMESPACE::ibzstream( filename.c_str() ); } #endif #if HAVE_ZLIB // gzip=8b1f 0808 (dec: 139 31 8 8) if( 0x1f == buff[0] && 0x8b == buff[1] ) // maybe a bug here? // this ordering is probably big/little endian dependent(?) { //COUT << "gzip!"<<std::endl; return new TOOLBOX_NAMESPACE::igzstream( filename.c_str() ); } #endif return new std::ifstream( filename.c_str() ); } std::ostream * get_ostream( const std::string & fname ) { switch( TOOLBOX_NAMESPACE::compression_policy() ) { #if HAVE_ZLIB case GZipCompression: return new TOOLBOX_NAMESPACE::ogzstream( fname.c_str() ); #endif #if HAVE_BZLIB case BZipCompression: return new TOOLBOX_NAMESPACE::obzstream( fname.c_str() ); #endif default: return new std::ofstream( fname.c_str() ); } } std::string bytes_from_file( const std::string &fn, unsigned int count, bool read_past_nl ) { typedef std::map<std::string,std::string> Map; static Map cache; Map::iterator it = cache.find( fn ); if( it != cache.end() ) return (*it).second; std::istream * is = 0; is = TOOLBOX_NAMESPACE::get_istream( fn ); if( ! is ) return std::string(); if( !is->good() ) { delete( is ); return std::string(); } is->unsetf(std::ios_base::skipws); std::string line; char c; for( unsigned int i = 0; i < count; i++ ) { *is >> c; if( (!read_past_nl) && '\n' == c ) break; if( ! is->good() ) break; line += c; } delete( is ); cache[fn] = line; return line; } } // namespace TOOLBOX_NAMESPACE --- NEW FILE: ns.file_util.h --- #ifndef TOOLKIT_FILE_UTIL_H_INCLUDED #define TOOLKIT_FILE_UTIL_H_INCLUDED 1 #include <string> namespace TOOLBOX_NAMESPACE { /** CompressionPolicy describes the framework-wide policy regarding compression when writing to files. (Sorry, pure stream-based compression isn't yet supported.) Setting to GZip/BZipCompression only enables compression if HAVE_ZLIB or HAVE_BZLIB ars set during library compilation, otherwise non-compressed streams are used in all cases. bzip compresses much better than gzip, but is notably slower. The speed should not make much of a difference unless you are working with very large data sets, and then you will notice that gzip is faster. Tip: you can use get_istream() on an arbitrary filename to get an appropriate input stream. Likewise, use get_ostream() to open writable a file with the policy-mandated stream type (if possible, defaulting to std::ofstream). */ enum CompressionPolicy { /** NoCompression implies just what it says - do not use compressed output streams. */ NoCompression = 1, /** GZipCompression means to use the TOOLBOX_NAMESPACE::ogzstream class for output streams. */ GZipCompression = 2, /** BZipCompression means to use the TOOLBOX_NAMESPACE::obzstream class for output streams. */ BZipCompression = 3 }; /** Sets the framework-wide CompressionPolicy preference. See the TOOLBOX_NAMESPACE::CompressionPolicy enum. */ void compression_policy( CompressionPolicy c ); /*... [truncated message content] |