1 /* Arg_parser - POSIX/GNU command line argument parser. (C version)
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
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
32 #include "carg_parser.h"
35 /* assure at least a minimum size for buffer `buf' */
36 static void * ap_resize_buffer( void * buf, const int min_size )
38 if( buf ) buf = realloc( buf, min_size );
39 else buf = malloc( min_size );
44 static char push_back_record( struct Arg_parser * const ap,
45 const int code, const char * const argument )
47 const int len = strlen( argument );
49 void * tmp = ap_resize_buffer( ap->data,
50 ( ap->data_size + 1 ) * sizeof (struct ap_Record) );
52 ap->data = (struct ap_Record *)tmp;
53 p = &(ap->data[ap->data_size]);
56 tmp = ap_resize_buffer( p->argument, len + 1 );
58 p->argument = (char *)tmp;
59 strncpy( p->argument, argument, len + 1 );
65 static char add_error( struct Arg_parser * const ap, const char * const msg )
67 const int len = strlen( msg );
68 void * tmp = ap_resize_buffer( ap->error, ap->error_size + len + 1 );
70 ap->error = (char *)tmp;
71 strncpy( ap->error + ap->error_size, msg, len + 1 );
72 ap->error_size += len;
77 static void free_data( struct Arg_parser * const ap )
80 for( i = 0; i < ap->data_size; ++i ) free( ap->data[i].argument );
81 if( ap->data ) { free( ap->data ); ap->data = 0; }
86 static char parse_long_option( struct Arg_parser * const ap,
87 const char * const opt, const char * const arg,
88 const struct ap_Option options[],
94 char exact = 0, ambig = 0;
96 for( len = 0; opt[len+2] && opt[len+2] != '='; ++len ) ;
98 /* Test all long options for either exact match or abbreviated matches. */
99 for( i = 0; options[i].code != 0; ++i )
100 if( options[i].name && !strncmp( options[i].name, &opt[2], len ) )
102 if( strlen( options[i].name ) == len ) /* Exact match found */
103 { index = i; exact = 1; break; }
104 else if( index < 0 ) index = i; /* First nonexact match found */
105 else if( options[index].code != options[i].code ||
106 options[index].has_arg != options[i].has_arg )
107 ambig = 1; /* Second or later nonexact match found */
110 if( ambig && !exact )
112 add_error( ap, "option `" ); add_error( ap, opt );
113 add_error( ap, "' is ambiguous" );
117 if( index < 0 ) /* nothing found */
119 add_error( ap, "unrecognized option `" ); add_error( ap, opt );
120 add_error( ap, "'" );
126 if( opt[len+2] ) /* `--<long_option>=<argument>' syntax */
128 if( options[index].has_arg == ap_no )
130 add_error( ap, "option `--" ); add_error( ap, options[index].name );
131 add_error( ap, "' doesn't allow an argument" );
134 if( options[index].has_arg == ap_yes && !opt[len+3] )
136 add_error( ap, "option `--" ); add_error( ap, options[index].name );
137 add_error( ap, "' requires an argument" );
140 return push_back_record( ap, options[index].code, &opt[len+3] );
143 if( options[index].has_arg == ap_yes )
145 if( !arg || !arg[0] )
147 add_error( ap, "option `--" ); add_error( ap, options[index].name );
148 add_error( ap, "' requires an argument" );
152 return push_back_record( ap, options[index].code, arg );
155 return push_back_record( ap, options[index].code, "" );
159 static char parse_short_option( struct Arg_parser * const ap,
160 const char * const opt, const char * const arg,
161 const struct ap_Option options[],
162 int * const argindp )
164 int cind = 1; /* character index in opt */
170 const unsigned char code = opt[cind];
172 code_str[0] = code; code_str[1] = 0;
175 for( i = 0; options[i].code; ++i )
176 if( code == options[i].code )
177 { index = i; break; }
181 add_error( ap, "invalid option -- " ); add_error( ap, code_str );
185 if( opt[++cind] == 0 ) { ++*argindp; cind = 0; } /* opt finished */
187 if( options[index].has_arg != ap_no && cind > 0 && opt[cind] )
189 if( !push_back_record( ap, code, &opt[cind] ) ) return 0;
190 ++*argindp; cind = 0;
192 else if( options[index].has_arg == ap_yes )
194 if( !arg || !arg[0] )
196 add_error( ap, "option requires an argument -- " );
197 add_error( ap, code_str );
200 ++*argindp; cind = 0;
201 if( !push_back_record( ap, code, arg ) ) return 0;
203 else if( !push_back_record( ap, code, "" ) ) return 0;
209 char ap_init( struct Arg_parser * const ap,
210 const int argc, const char * const argv[],
211 const struct ap_Option options[], const char in_order )
213 const char ** non_options = 0; /* skipped non-options */
214 int non_options_size = 0; /* number of skipped non-options */
215 int argind = 1; /* index in argv */
222 if( argc < 2 || !argv || !options ) return 1;
224 while( argind < argc )
226 const unsigned char ch1 = argv[argind][0];
227 const unsigned char ch2 = ( ch1 ? argv[argind][1] : 0 );
229 if( ch1 == '-' && ch2 ) /* we found an option */
231 const char * const opt = argv[argind];
232 const char * const arg = (argind + 1 < argc) ? argv[argind+1] : 0;
235 if( !argv[argind][2] ) { ++argind; break; } /* we found "--" */
236 else if( !parse_long_option( ap, opt, arg, options, &argind ) ) return 0;
238 else if( !parse_short_option( ap, opt, arg, options, &argind ) ) return 0;
239 if( ap->error ) break;
245 void * tmp = ap_resize_buffer( non_options,
246 ( non_options_size + 1 ) * sizeof *non_options );
248 non_options = (const char **)tmp;
249 non_options[non_options_size++] = argv[argind++];
251 else if( !push_back_record( ap, 0, argv[argind++] ) ) return 0;
254 if( ap->error ) free_data( ap );
257 for( i = 0; i < non_options_size; ++i )
258 if( !push_back_record( ap, 0, non_options[i] ) ) return 0;
259 while( argind < argc )
260 if( !push_back_record( ap, 0, argv[argind++] ) ) return 0;
262 if( non_options ) free( non_options );
267 void ap_free( struct Arg_parser * const ap )
270 if( ap->error ) { free( ap->error ); ap->error = 0; }
275 const char * ap_error( const struct Arg_parser * const ap )
276 { return ap->error; }
279 int ap_arguments( const struct Arg_parser * const ap )
280 { return ap->data_size; }
283 int ap_code( const struct Arg_parser * const ap, const int i )
285 if( i >= 0 && i < ap_arguments( ap ) ) return ap->data[i].code;
290 const char * ap_argument( const struct Arg_parser * const ap, const int i )
292 if( i >= 0 && i < ap_arguments( ap ) ) return ap->data[i].argument;