/* ** PJL C++ Library ** option_stream.h ** ** Copyright (C) 1999 Paul J. Lucas ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program 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 General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef option_stream_H #define option_stream_H // standard #include #if 0 extern char const* dtoa( double ); // local #include "itoa.h" #include "util.h" #endif namespace PJL { //***************************************************************************** // // SYNOPSIS // class option_stream // // DESCRIPTION // // Given the traditional argc and argv for command-line arguments, extract // options from them following the stream model. // // RATIONALE // // Why not use the standard getopt() or GNU's getopt_long()? Because // neither are thread-safe and I needed a thread-safe version. // //***************************************************************************** { public: enum { os_arg_none = 0, os_arg_req = 1, os_arg_opt = 2 }; struct spec { // // A spec gives a specfication for an option: its long name, its // argument type, and it's short option equivalent. A null-terminated // array of specs is given to the option_stream constructor. // // The arg_type takes on one of the above enum values, but is not // declared as an enum to allow the integer values to be used as a // shorthand. // // Regardless of whether the user enters a long or a short option, it // is the short option character that is returned to the caller in // order to be able to use a simple switch statement to do different // things depending on the option. // // If, for a given long option there is to be no short option // equivalent, then the caller has to make up bogus ones that the user // will never type. Either the ASCII control or high characters can be // user for this. The null character may not be used. // #if 0 // // Ignore the class in this section. I'm not sure I want to implement // default values for options that can have optional arguments. I left // the code here in case I ever decide I want to implement it. // class default_value { public: default_value( char v ) : val_( new char[2] ) { val_[0] = v; val_[1] = '\0'; } default_value( char const *v = "" ) : val_( new_strdup( v ) ) { } default_value( long v ) : val_( new_strdup( ltoa( v ) ) ) { } default_value( double v ) : val_( new_strdup( dtoa( v ) ) ) { } default_value( default_value const &v ) : val_( new_strdup( v.val_ ) ) { } ~default_value() { delete[] val_; } operator char*() const { return val_; } private: char *const val_; default_value& operator=( default_value const& ); }; #endif char const* long_name; short arg_type; unsigned char short_name; #if 0 default_value def_arg; #endif }; option_stream( int argc, char *argv[], spec const[], std::ostream& = std::cerr ); int shift() const { return argi_; } operator bool() const { return !end_; } class option { // // An option is what is extracted from an option_stream. Its operator // char() gives which option it is and arg() gives its argument, if // any. For options that do not have an argument, arg() returns the // null pointer. // // An option may be copied in which case it has a private copy of its // argument. // public: option( char c = '\0', char *a = 0 ) : short_name_( c ), arg_( a ) { } char* arg() const { return arg_; } operator char() const { return short_name_; } friend option_stream& operator>>( option_stream&, option& ); private: char short_name_; char* arg_; option( option const& ); // forbid copy option& operator=( option const& ); // forbid assignment }; friend option_stream& operator>>( option_stream&, option& ); private: int argc_; // argument count from main() char** argv_; // argument vector from main() spec const* specs_; // the option specifications std::ostream& err_; // ostream to write wrrors to int argi_; // current index into argv_[] char* next_c_; // next char in group of short options bool end_; // reached end of options? }; } // namespace PJL #endif /* option_stream_H */ /* vim:set et sw=4 ts=4: */