50 std::size_t ignore_non_options , std::function<std::string(
const std::string&,
bool)> callback_fn )
53 return parser.
parse( args_in , start_position , ignore_non_options , callback_fn ) ;
57 std::size_t ignore_non_options , std::function<std::string(
const std::string&,
bool)> callback_fn )
60 std::size_t i = start ;
61 for( ; i < args_in.size() ; i++ )
63 const std::string & arg = args_in.at(i) ;
71 if( isAnOptionSet(arg) )
73 for( std::size_t n = 1U ; n < arg.length() ; n++ )
75 char c = arg.at( n ) ;
76 bool discard = callback_fn ? callback_fn(m_spec.lookup(c),
true).substr(0,1) ==
"-" : false ;
78 processOptionOn( c ) ;
81 else if( isOldOption(arg) )
84 bool discard = callback_fn ? callback_fn(m_spec.lookup(c),
true).substr(0,1) ==
"-" : false ;
86 i += ( ( m_spec.valued(c) && !m_spec.defaulting(c) ) ? 1U : 0U ) ;
87 else if( m_spec.valued(c) && !m_spec.defaulting(c) && (i+1U) >= args_in.size() )
89 else if( m_spec.valued(c) && !m_spec.defaulting(c) )
90 processOption( c , args_in.at(++i) ) ;
92 processOptionOn( c ) ;
94 else if( isNewOption(arg) )
96 std::string key_value = arg.substr( 2U ) ;
97 std::size_t pos_eq = eqPos( key_value ) ;
98 bool has_eq = pos_eq != std::string::npos ;
99 std::string key_in = has_eq ? key_value.substr(0U,pos_eq) : key_value ;
100 std::string value = eqValue( key_value , pos_eq ) ;
101 std::string key = callback_fn ? callback_fn(key_in,
false) : key_in ;
102 bool discard = !key.empty() && key.at( 0U ) ==
'-' ;
103 key = key.substr( discard ? 1U : 0U ) ;
105 i += ( (m_spec.valued(key) && !m_spec.defaulting(key) && !has_eq) ? 1U : 0U ) ;
107 processOptionOn( key ) ;
109 processOptionOff( key ) ;
111 processOption( key , value ,
false ) ;
112 else if( m_spec.defaulting(key) )
113 processOption( key , std::string() ,
false ) ;
114 else if( m_spec.valued(key) && (i+1U) >= args_in.size() )
115 errorNoValue( key ) ;
116 else if( m_spec.valued(key) )
117 processOption( key , args_in.at(++i) ,
true ) ;
119 processOptionOn( key ) ;
121 else if( ignore_non_options != 0U )
123 --ignore_non_options ;
124 args_out.push_back( arg ) ;
131 for( ; i < args_in.size() ; i++ )
132 args_out.push_back( args_in.at(i) ) ;
136void G::OptionParser::processOptionOn(
const std::string & name )
138 if( !m_spec.valid(name) )
139 errorUnknownOption( name ) ;
140 else if( m_spec.valued(name) && !m_spec.defaulting(name) )
141 errorNoValue( name ) ;
142 else if( haveSeenOff(name) )
143 errorConflict( name ) ;
144 else if( haveSeenOn(name) )
145 m_map.increment( name ) ;
150void G::OptionParser::processOptionOff(
const std::string & name )
152 if( !m_spec.valid(name) )
153 errorUnknownOption( name ) ;
154 else if( m_spec.valued(name) )
155 errorNoValue( name ) ;
156 else if( haveSeenOn(name) )
157 errorConflict( name ) ;
158 else if( haveSeenOff(name) )
159 m_map.increment( name ) ;
164void G::OptionParser::processOption(
const std::string & name ,
const std::string & value ,
165 bool fail_if_dubious_value )
167 if( !m_spec.valid(name) )
168 errorUnknownOption( name ) ;
169 else if( !value.empty() && value[0] ==
'-' && fail_if_dubious_value )
170 errorDubiousValue( name , value ) ;
171 else if( !m_spec.valued(name) && !value.empty() )
172 errorExtraValue( name , value ) ;
173 else if( m_spec.multivalued(name) )
174 m_map.insert( OptionMap::value_type(name,OptionValue(value,valueCount(value))) ) ;
175 else if( haveSeen(name) && !haveSeenSame(name,value) )
176 errorDuplicate( name ) ;
177 else if( haveSeen(name) )
178 m_map.increment( name ) ;
180 m_map.insert( OptionMap::value_type(name,OptionValue(value)) ) ;
183void G::OptionParser::processOptionOn(
char c )
185 std::string name = m_spec.lookup( c ) ;
186 if( !m_spec.valid(name) )
187 errorUnknownOption( c ) ;
188 else if( m_spec.valued(name) && !m_spec.defaulting(name) )
190 else if( haveSeenOff(name) )
191 errorConflict( name ) ;
192 else if( haveSeenOn(name) )
193 m_map.increment( name ) ;
198void G::OptionParser::processOption(
char c ,
const std::string & value )
200 std::string name = m_spec.lookup( c ) ;
201 if( !m_spec.valid(name) )
202 errorUnknownOption( c ) ;
203 else if( !m_spec.valued(name) && !value.empty() )
204 errorExtraValue( name , value ) ;
205 else if( m_spec.multivalued(c) )
206 m_map.insert( OptionMap::value_type(name,OptionValue(value,valueCount(value))) ) ;
207 else if( haveSeen(name) && !haveSeenSame(name,value) )
208 errorDuplicate( c ) ;
209 else if( haveSeen(name) )
210 m_map.increment( name ) ;
212 m_map.insert( OptionMap::value_type(name,OptionValue(value)) ) ;
215std::string::size_type G::OptionParser::eqPos(
const std::string & s )
217 std::string::size_type p = s.find_first_not_of(
"abcdefghijklmnopqrstuvwxyz0123456789-_" ) ;
218 return p != std::string::npos && s.at(p) ==
'=' ? p : std::string::npos ;
221std::string G::OptionParser::eqValue(
const std::string & s , std::string::size_type pos )
223 return (pos+1U) == s.length() ? std::string() : s.substr(pos+1U) ;
226bool G::OptionParser::isOldOption(
const std::string & arg )
229 ( arg.length() > 1U && arg.at(0U) ==
'-' ) &&
230 ! isNewOption( arg ) ;
233bool G::OptionParser::isNewOption(
const std::string & arg )
235 return arg.length() > 2U && arg.at(0U) ==
'-' && arg.at(1U) ==
'-' ;
238bool G::OptionParser::isAnOptionSet(
const std::string & arg )
240 return isOldOption(arg) && arg.length() > 2U ;
243void G::OptionParser::errorDubiousValue(
const std::string & name ,
const std::string & value )
246 format(
txt(
"%1% is probably a mistake, use %2% or %3%")) %
247 (
"\"--"+name+
" "+value+
"\"") %
248 (
"\"--"+name+
"=... "+value+
"\"") %
249 (
"\"--"+name+
"="+value+
"\"") ) ;
255 error( str( format(
txt(
"duplicate use of %1%")) % (
"\"-"+std::string(1U,c)+
"\"") ) ) ;
260 error( str(
format(
txt(
"duplicate use of %1%")) % (
"\"--"+name+
"\"") ) ) ;
264void G::OptionParser::errorExtraValue(
char c ,
const std::string & )
266 error( str(
format(
txt(
"cannot give a value with %1%")) % (
"\"-"+std::string(1U,c)+
"\"") ) ) ;
270void G::OptionParser::errorExtraValue(
const std::string & name ,
const std::string & value )
272 error( str( format(
txt(
"cannot give a value with %1% (%2%)")) % (
"\"--"+name+
"\"") % value ) ) ;
275void G::OptionParser::errorNoValue(
char c )
277 error( str( format(
txt(
"no value supplied for %1%")) % (
"-"+std::string(1U,c)) ) ) ;
280void G::OptionParser::errorNoValue(
const std::string & name )
282 error( str( format(
txt(
"no value supplied for %1%")) % (
"\"--"+name+
"\"") ) ) ;
285void G::OptionParser::errorUnknownOption(
char c )
287 error( str( format(
txt(
"invalid option: %1%")) % (
"\"-"+std::string(1U,c)+
"\"") ) ) ;
290void G::OptionParser::errorUnknownOption(
const std::string & name )
292 error( str( format(
txt(
"invalid option: %1%")) % (
"\"--"+name+
"\"") ) ) ;
295void G::OptionParser::errorConflict(
const std::string & name )
297 error( str( format(
txt(
"conflicting values: %1%")) % (
"\"--"+name+
"\"") ) ) ;
300void G::OptionParser::error(
const std::string & s )
303 m_errors->push_back( s ) ;
306bool G::OptionParser::haveSeenOn(
const std::string & name )
const
308 auto p = m_map.find( name ) ;
309 return p != m_map.end() && !(*p).second.isOff() ;
312bool G::OptionParser::haveSeenOff(
const std::string & name )
const
314 auto p = m_map.find( name ) ;
315 return p != m_map.end() && (*p).second.isOff() ;
318bool G::OptionParser::haveSeen(
const std::string & name )
const
320 return m_map.find(name) != m_map.end() ;
323bool G::OptionParser::haveSeenSame(
const std::string & name ,
const std::string & value )
const
325 auto p = m_map.find( name ) ;
326 return p != m_map.end() && (*p).second.value() == value ;
329std::size_t G::OptionParser::valueCount(
const std::string & s )
331 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.
StringArray parse(const StringArray &args_in, std::size_t start_position=1U, std::size_t ignore_non_options=0U, std::function< std::string(const std::string &, bool)> callback_fn={})
Parses the given command-line arguments into the value map and/or error list defined by the construct...
OptionParser(const Options &spec, OptionMap &values_out, StringArray &errors_out)
Constructor.
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 assemble a list of command-line options and provide access by name.
static bool isPositive(std::string_view) noexcept
Returns true if the string has a positive meaning, such as "1", "true", "yes".
static bool isNegative(std::string_view) noexcept
Returns true if the string has a negative meaning, such as "0", "false", "no".
std::vector< std::string > StringArray
A std::vector of std::strings.
const char * txt(const char *p) noexcept
A briefer alternative to G::gettext().