1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
/*
** 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 <iostream>
#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: */
|