1 // Arg_parser - A POSIX/GNU command line argument parser.
2 // Copyright (C) 2006, 2007, 2008, 2009, 2010 Antonio Diaz Diaz.
3 // Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
5 // This program 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 program 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 program. If not, see <http://www.gnu.org/licenses/>.
23 #include "arg_parser.h"
26 bool Arg_parser::parse_long_option( const char * const opt
, const char * const arg
,
27 const Option options
[], int & argind
) throw()
31 bool exact
= false, ambig
= false;
33 for( len
= 0; opt
[len
+2] && opt
[len
+2] != '='; ++len
) ;
35 // Test all long options for either exact match or abbreviated matches.
36 for( int i
= 0; options
[i
].code
!= 0; ++i
)
37 if( options
[i
].name
&& !std::strncmp( options
[i
].name
, &opt
[2], len
) )
39 if( std::strlen( options
[i
].name
) == len
) // Exact match found
40 { index
= i
; exact
= true; break; }
41 else if( index
< 0 ) index
= i
; // First nonexact match found
42 else if( options
[index
].code
!= options
[i
].code
||
43 options
[index
].has_arg
!= options
[i
].has_arg
)
44 ambig
= true; // Second or later nonexact match found
49 _error
= "option `"; _error
+= opt
; _error
+= "' is ambiguous";
53 if( index
< 0 ) // nothing found
55 _error
= "unrecognized option `"; _error
+= opt
; _error
+= '\'';
60 data
.push_back( Record( options
[index
].code
) );
62 if( opt
[len
+2] ) // `--<long_option>=<argument>' syntax
64 if( options
[index
].has_arg
== no
)
66 _error
= "option `--"; _error
+= options
[index
].name
;
67 _error
+= "' doesn't allow an argument";
70 if( options
[index
].has_arg
== yes
&& !opt
[len
+3] )
72 _error
= "option `--"; _error
+= options
[index
].name
;
73 _error
+= "' requires an argument";
76 data
.back().argument
= &opt
[len
+3];
80 if( options
[index
].has_arg
== yes
)
84 _error
= "option `--"; _error
+= options
[index
].name
;
85 _error
+= "' requires an argument";
88 ++argind
; data
.back().argument
= arg
;
96 bool Arg_parser::parse_short_option( const char * const opt
, const char * const arg
,
97 const Option options
[], int & argind
) throw()
99 int cind
= 1; // character index in opt
104 const unsigned char code
= opt
[cind
];
107 for( int i
= 0; options
[i
].code
; ++i
)
108 if( code
== options
[i
].code
)
109 { index
= i
; break; }
113 _error
= "invalid option -- "; _error
+= code
;
117 data
.push_back( Record( code
) );
118 if( opt
[++cind
] == 0 ) { ++argind
; cind
= 0; } // opt finished
120 if( options
[index
].has_arg
!= no
&& cind
> 0 && opt
[cind
] )
122 data
.back().argument
= &opt
[cind
]; ++argind
; cind
= 0;
124 else if( options
[index
].has_arg
== yes
)
126 if( !arg
|| !arg
[0] )
128 _error
= "option requires an argument -- "; _error
+= code
;
131 data
.back().argument
= arg
; ++argind
; cind
= 0;
138 Arg_parser::Arg_parser( const int argc
, const char * const argv
[],
139 const Option options
[], const bool in_order
) throw()
141 if( argc
< 2 || !argv
|| !options
) return;
143 std::vector
< std::string
> non_options
; // skipped non-options
144 int argind
= 1; // index in argv
146 while( argind
< argc
)
148 const unsigned char ch1
= argv
[argind
][0];
149 const unsigned char ch2
= ( ch1
? argv
[argind
][1] : 0 );
151 if( ch1
== '-' && ch2
) // we found an option
153 const char * const opt
= argv
[argind
];
154 const char * const arg
= (argind
+ 1 < argc
) ? argv
[argind
+1] : 0;
157 if( !argv
[argind
][2] ) { ++argind
; break; } // we found "--"
158 else if( !parse_long_option( opt
, arg
, options
, argind
) ) break;
160 else if( !parse_short_option( opt
, arg
, options
, argind
) ) break;
164 if( !in_order
) non_options
.push_back( argv
[argind
++] );
165 else { data
.push_back( Record() ); data
.back().argument
= argv
[argind
++]; }
168 if(! _error
.empty() ) data
.clear();
171 for( unsigned int i
= 0; i
< non_options
.size(); ++i
)
172 { data
.push_back( Record() ); data
.back().argument
.swap( non_options
[i
] ); }
173 while( argind
< argc
)
174 { data
.push_back( Record() ); data
.back().argument
= argv
[argind
++]; }
179 Arg_parser::Arg_parser( const char * const opt
, const char * const arg
,
180 const Option options
[] ) throw()
182 if( !opt
|| !opt
[0] || !options
) return;
184 if( opt
[0] == '-' && opt
[1] ) // we found an option
186 int argind
= 1; // dummy
188 { if( opt
[2] ) parse_long_option( opt
, arg
, options
, argind
); }
190 parse_short_option( opt
, arg
, options
, argind
);
191 if(! _error
.empty() ) data
.clear();
193 else { data
.push_back( Record() ); data
.back().argument
= opt
; }