1
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
2
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
5
This library is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this library. If not, see <http://www.gnu.org/licenses/>.
18
As a special exception, you may use this file as part of a free
19
software library without restriction. Specifically, if other files
20
instantiate templates or use macros or inline functions from this
21
file, or you compile this file and link it with other files to
22
produce an executable, this file does not by itself cause the
23
resulting executable to be covered by the GNU General Public
24
License. This exception does not however invalidate any other
25
reasons why the executable file might be covered by the GNU General
33
#include "arg_parser.h"
36
bool Arg_parser::parse_long_option( const char * const opt, const char * const arg,
37
const Option options[], int & argind )
41
bool exact = false, ambig = false;
43
for( len = 0; opt[len+2] && opt[len+2] != '='; ++len ) ;
45
// Test all long options for either exact match or abbreviated matches.
46
for( int i = 0; options[i].code != 0; ++i )
47
if( options[i].name && std::strncmp( options[i].name, &opt[2], len ) == 0 )
49
if( std::strlen( options[i].name ) == len ) // Exact match found
50
{ index = i; exact = true; break; }
51
else if( index < 0 ) index = i; // First nonexact match found
52
else if( options[index].code != options[i].code ||
53
options[index].has_arg != options[i].has_arg )
54
ambig = true; // Second or later nonexact match found
59
error_ = "option '"; error_ += opt; error_ += "' is ambiguous";
63
if( index < 0 ) // nothing found
65
error_ = "unrecognized option '"; error_ += opt; error_ += '\'';
70
data.push_back( Record( options[index].code ) );
72
if( opt[len+2] ) // '--<long_option>=<argument>' syntax
74
if( options[index].has_arg == no )
76
error_ = "option '--"; error_ += options[index].name;
77
error_ += "' doesn't allow an argument";
80
if( options[index].has_arg == yes && !opt[len+3] )
82
error_ = "option '--"; error_ += options[index].name;
83
error_ += "' requires an argument";
86
data.back().argument = &opt[len+3];
90
if( options[index].has_arg == yes )
94
error_ = "option '--"; error_ += options[index].name;
95
error_ += "' requires an argument";
98
++argind; data.back().argument = arg;
106
bool Arg_parser::parse_short_option( const char * const opt, const char * const arg,
107
const Option options[], int & argind )
109
int cind = 1; // character index in opt
114
const unsigned char c = opt[cind];
117
for( int i = 0; options[i].code; ++i )
118
if( c == options[i].code )
119
{ index = i; break; }
123
error_ = "invalid option -- "; error_ += c;
127
data.push_back( Record( c ) );
128
if( opt[++cind] == 0 ) { ++argind; cind = 0; } // opt finished
130
if( options[index].has_arg != no && cind > 0 && opt[cind] )
132
data.back().argument = &opt[cind]; ++argind; cind = 0;
134
else if( options[index].has_arg == yes )
136
if( !arg || !arg[0] )
138
error_ = "option requires an argument -- "; error_ += c;
141
data.back().argument = arg; ++argind; cind = 0;
148
Arg_parser::Arg_parser( const int argc, const char * const argv[],
149
const Option options[], const bool in_order )
151
if( argc < 2 || !argv || !options ) return;
153
std::vector< std::string > non_options; // skipped non-options
154
int argind = 1; // index in argv
156
while( argind < argc )
158
const unsigned char ch1 = argv[argind][0];
159
const unsigned char ch2 = ( ch1 ? argv[argind][1] : 0 );
161
if( ch1 == '-' && ch2 ) // we found an option
163
const char * const opt = argv[argind];
164
const char * const arg = (argind + 1 < argc) ? argv[argind+1] : 0;
167
if( !argv[argind][2] ) { ++argind; break; } // we found "--"
168
else if( !parse_long_option( opt, arg, options, argind ) ) break;
170
else if( !parse_short_option( opt, arg, options, argind ) ) break;
174
if( !in_order ) non_options.push_back( argv[argind++] );
175
else { data.push_back( Record() ); data.back().argument = argv[argind++]; }
178
if( error_.size() ) data.clear();
181
for( unsigned i = 0; i < non_options.size(); ++i )
182
{ data.push_back( Record() ); data.back().argument.swap( non_options[i] ); }
183
while( argind < argc )
184
{ data.push_back( Record() ); data.back().argument = argv[argind++]; }
189
Arg_parser::Arg_parser( const char * const opt, const char * const arg,
190
const Option options[] )
192
if( !opt || !opt[0] || !options ) return;
194
if( opt[0] == '-' && opt[1] ) // we found an option
196
int argind = 1; // dummy
198
{ if( opt[2] ) parse_long_option( opt, arg, options, argind ); }
200
parse_short_option( opt, arg, options, argind );
201
if( error_.size() ) data.clear();
203
else { data.push_back( Record() ); data.back().argument = opt; }