update copyright date
[gnash.git] / libbase / arg_parser.cpp
blob3cf1eebb060847583160552925ec890c273421fb
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.
4 //
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.
9 //
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/>.
19 #include <cstring>
20 #include <string>
21 #include <vector>
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()
29 unsigned int len;
30 int index = -1;
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
47 if( ambig && !exact )
49 _error = "option `"; _error += opt; _error += "' is ambiguous";
50 return false;
53 if( index < 0 ) // nothing found
55 _error = "unrecognized option `"; _error += opt; _error += '\'';
56 return false;
59 ++argind;
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";
68 return false;
70 if( options[index].has_arg == yes && !opt[len+3] )
72 _error = "option `--"; _error += options[index].name;
73 _error += "' requires an argument";
74 return false;
76 data.back().argument = &opt[len+3];
77 return true;
80 if( options[index].has_arg == yes )
82 if( !arg )
84 _error = "option `--"; _error += options[index].name;
85 _error += "' requires an argument";
86 return false;
88 ++argind; data.back().argument = arg;
89 return true;
92 return true;
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
101 while( cind > 0 )
103 int index = -1;
104 const unsigned char code = opt[cind];
106 if( code != 0 )
107 for( int i = 0; options[i].code; ++i )
108 if( code == options[i].code )
109 { index = i; break; }
111 if( index < 0 )
113 _error = "invalid option -- "; _error += code;
114 return false;
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;
129 return false;
131 data.back().argument = arg; ++argind; cind = 0;
134 return true;
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;
155 if( ch2 == '-' )
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;
162 else
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();
169 else
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
187 if( opt[1] == '-' )
188 { if( opt[2] ) parse_long_option( opt, arg, options, argind ); }
189 else
190 parse_short_option( opt, arg, options, argind );
191 if(! _error.empty() ) data.clear();
193 else { data.push_back( Record() ); data.back().argument = opt; }