49 std::size_t ignore_non_options )
52 return parser.
parse( args_in , start_position , ignore_non_options ) ;
56 std::size_t ignore_non_options )
59 std::size_t i = start ;
60 for( ; i < args_in.size() ; i++ )
62 const std::string & arg = args_in.at(i) ;
70 if( isAnOptionSet(arg) )
72 for( std::size_t n = 1U ; n < arg.length() ; n++ )
73 processOptionOn( arg.at(n) ) ;
75 else if( isOldOption(arg) )
78 if( m_spec.valued(c) && (i+1U) >= args_in.size() )
80 else if( m_spec.valued(c) )
81 processOption( c , args_in.at(++i) ) ;
83 processOptionOn( c ) ;
85 else if( isNewOption(arg) )
87 std::string name = arg.substr( 2U ) ;
88 std::string::size_type pos_eq = eqPos( name ) ;
89 bool has_eq = pos_eq != std::string::npos ;
90 std::string key = has_eq ? name.substr(0U,pos_eq) : name ;
91 if( has_eq && m_spec.unvalued(key) &&
Str::isPositive(eqValue(name,pos_eq)) )
92 processOptionOn( key ) ;
93 else if( has_eq && m_spec.unvalued(key) &&
Str::isNegative(eqValue(name,pos_eq)) )
94 processOptionOff( key ) ;
96 processOption( key , eqValue(name,pos_eq) ,
false ) ;
97 else if( m_spec.defaulting(name) )
98 processOption( key , std::string() ,
false ) ;
99 else if( m_spec.valued(name) && (i+1U) >= args_in.size() )
100 errorNoValue( name ) ;
101 else if( m_spec.valued(name) )
102 processOption( name , args_in.at(++i) ,
true ) ;
104 processOptionOn( name ) ;
106 else if( ignore_non_options != 0U )
108 --ignore_non_options ;
109 args_out.push_back( arg ) ;
116 for( ; i < args_in.size() ; i++ )
117 args_out.push_back( args_in.at(i) ) ;
121void G::OptionParser::processOptionOn(
const std::string & name )
123 if( !m_spec.valid(name) )
124 errorUnknownOption( name ) ;
125 else if( m_spec.valued(name) )
126 errorNoValue( name ) ;
127 else if( haveSeenOff(name) )
128 errorConflict( name ) ;
129 else if( haveSeenOn(name) )
130 m_map.increment( name ) ;
135void G::OptionParser::processOptionOff(
const std::string & name )
137 if( !m_spec.valid(name) )
138 errorUnknownOption( name ) ;
139 else if( m_spec.valued(name) )
140 errorNoValue( name ) ;
141 else if( haveSeenOn(name) )
142 errorConflict( name ) ;
143 else if( haveSeenOff(name) )
144 m_map.increment( name ) ;
149void G::OptionParser::processOption(
const std::string & name ,
const std::string & value ,
150 bool fail_if_dubious_value )
152 if( !m_spec.valid(name) )
153 errorUnknownOption( name ) ;
154 else if( !value.empty() && value[0] ==
'-' && fail_if_dubious_value )
155 errorDubiousValue( name , value ) ;
156 else if( !m_spec.valued(name) && !value.empty() )
157 errorExtraValue( name , value ) ;
158 else if( m_spec.multivalued(name) )
159 m_map.insert( OptionMap::value_type(name,OptionValue(value,valueCount(value))) ) ;
160 else if( haveSeen(name) && !haveSeenSame(name,value) )
161 errorDuplicate( name ) ;
162 else if( haveSeen(name) )
163 m_map.increment( name ) ;
165 m_map.insert( OptionMap::value_type(name,OptionValue(value)) ) ;
168void G::OptionParser::processOptionOn(
char c )
170 std::string name = m_spec.lookup( c ) ;
171 if( !m_spec.valid(name) )
172 errorUnknownOption( c ) ;
173 else if( m_spec.valued(name) )
175 else if( haveSeenOff(name) )
176 errorConflict( name ) ;
177 else if( haveSeenOn(name) )
178 m_map.increment( name ) ;
183void G::OptionParser::processOption(
char c ,
const std::string & value )
185 std::string name = m_spec.lookup( c ) ;
186 if( !m_spec.valid(name) )
187 errorUnknownOption( c ) ;
188 else if( !m_spec.valued(name) && !value.empty() )
189 errorExtraValue( name , value ) ;
190 else if( m_spec.multivalued(c) )
191 m_map.insert( OptionMap::value_type(name,OptionValue(value,valueCount(value))) ) ;
192 else if( haveSeen(name) && !haveSeenSame(name,value) )
193 errorDuplicate( c ) ;
194 else if( haveSeen(name) )
195 m_map.increment( name ) ;
197 m_map.insert( OptionMap::value_type(name,OptionValue(value)) ) ;
200std::string::size_type G::OptionParser::eqPos(
const std::string & s )
202 std::string::size_type p = s.find_first_not_of(
"abcdefghijklmnopqrstuvwxyz0123456789-_" ) ;
203 return p != std::string::npos && s.at(p) ==
'=' ? p : std::string::npos ;
206std::string G::OptionParser::eqValue(
const std::string & s , std::string::size_type pos )
208 return (pos+1U) == s.length() ? std::string() : s.substr(pos+1U) ;
211bool G::OptionParser::isOldOption(
const std::string & arg )
214 ( arg.length() > 1U && arg.at(0U) ==
'-' ) &&
215 ! isNewOption( arg ) ;
218bool G::OptionParser::isNewOption(
const std::string & arg )
220 return arg.length() > 2U && arg.at(0U) ==
'-' && arg.at(1U) ==
'-' ;
223bool G::OptionParser::isAnOptionSet(
const std::string & arg )
225 return isOldOption(arg) && arg.length() > 2U ;
228void G::OptionParser::errorDubiousValue(
const std::string & name ,
const std::string & value )
231 format(
G::gettext(
"%1% is probably a mistake, use %2% or %3%")) %
232 (
"\"--"+name+
" "+value+
"\"") %
233 (
"\"--"+name+
"=... "+value+
"\"") %
234 (
"\"--"+name+
"="+value+
"\"") ) ;
240 error( str( format(
gettext(
"duplicate use of %1%")) % (
"\"-"+std::string(1U,c)+
"\"") ) ) ;
245 error( str(
format(
gettext(
"duplicate use of %1%")) % (
"\"--"+name+
"\"") ) ) ;
248void G::OptionParser::errorExtraValue(
char c ,
const std::string & )
250 error( str(
format(
gettext(
"cannot give a value with %1%")) % (
"\"-"+std::string(1U,c)+
"\"") ) ) ;
253void G::OptionParser::errorExtraValue(
const std::string & name ,
const std::string & value )
255 error( str( format(
gettext(
"cannot give a value with %1% (%2%)")) % (
"\"--"+name+
"\"") % value ) ) ;
258void G::OptionParser::errorNoValue(
char c )
260 error( str( format(
gettext(
"no value supplied for %1%")) % (
"-"+std::string(1U,c)) ) ) ;
263void G::OptionParser::errorNoValue(
const std::string & name )
265 error( str( format(
gettext(
"no value supplied for %1%")) % (
"\"--"+name+
"\"") ) ) ;
268void G::OptionParser::errorUnknownOption(
char c )
270 error( str( format(
gettext(
"invalid option: %1%")) % (
"\"-"+std::string(1U,c)+
"\"") ) ) ;
273void G::OptionParser::errorUnknownOption(
const std::string & name )
275 error( str( format(
gettext(
"invalid option: %1%")) % (
"\"--"+name+
"\"") ) ) ;
278void G::OptionParser::errorConflict(
const std::string & name )
280 error( str( format(
gettext(
"conflicting values: %1%")) % (
"\"--"+name+
"\"") ) ) ;
283void G::OptionParser::error(
const std::string & s )
286 m_errors->push_back( s ) ;
289bool G::OptionParser::haveSeenOn(
const std::string & name )
const
291 auto p = m_map.find( name ) ;
292 return p != m_map.end() && !(*p).second.isOff() ;
295bool G::OptionParser::haveSeenOff(
const std::string & name )
const
297 auto p = m_map.find( name ) ;
298 return p != m_map.end() && (*p).second.isOff() ;
301bool G::OptionParser::haveSeen(
const std::string & name )
const
303 return m_map.find(name) != m_map.end() ;
306bool G::OptionParser::haveSeenSame(
const std::string & name ,
const std::string & value )
const
308 auto p = m_map.find( name ) ;
309 return p != m_map.end() && (*p).second.value() == value ;
312std::size_t G::OptionParser::valueCount(
const std::string & s )
314 return 1U + std::count( s.begin() , s.end() ,
',' ) ;
A multimap-like container for command-line options and their values.
A parser for command-line arguments that operates according to an Options specification and returns a...
void errorDuplicate(const std::string &)
Adds a 'duplicate' error in the constructor's error list for the given option.
OptionParser(const Options &spec, OptionMap &values_out, StringArray &errors_out)
Constructor.
StringArray parse(const StringArray &args_in, std::size_t start_position=1U, std::size_t ignore_non_options=0U)
Parses the given command-line arguments into the value map and/or error list defined by the construct...
static OptionValue on()
A factory function for an unvalued option-enabled option.
static OptionValue off()
A factory function for an unvalued option-disabled option.
A class to represent allowed command-line options and to provide command-line usage text.
static bool isNegative(const std::string &)
Returns true if the string has a negative meaning, such as "0", "false", "no".
static bool isPositive(const std::string &)
Returns true if the string has a positive meaning, such as "1", "true", "yes".
std::vector< std::string > StringArray
A std::vector of std::strings.
const char * gettext(const char *)
Returns the message translation in the current locale's codeset, eg.