1 /* Arg_parser - POSIX/GNU command line argument parser. (C version)
2 Copyright (C) 2006-2015 Antonio Diaz Diaz.
4 This library is free software. Redistribution and use in source and
5 binary forms, with or without modification, are permitted provided
6 that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 #include "carg_parser.h"
26 /* assure at least a minimum size for buffer 'buf' */
27 static void * ap_resize_buffer( void * buf, const int min_size )
29 if( buf ) buf = realloc( buf, min_size );
30 else buf = malloc( min_size );
35 static char push_back_record( struct Arg_parser * const ap,
36 const int code, const char * const argument )
38 const int len = strlen( argument );
40 void * tmp = ap_resize_buffer( ap->data,
41 ( ap->data_size + 1 ) * sizeof (struct ap_Record) );
43 ap->data = (struct ap_Record *)tmp;
44 p = &(ap->data[ap->data_size]);
47 tmp = ap_resize_buffer( p->argument, len + 1 );
49 p->argument = (char *)tmp;
50 strncpy( p->argument, argument, len + 1 );
56 static char add_error( struct Arg_parser * const ap, const char * const msg )
58 const int len = strlen( msg );
59 void * tmp = ap_resize_buffer( ap->error, ap->error_size + len + 1 );
61 ap->error = (char *)tmp;
62 strncpy( ap->error + ap->error_size, msg, len + 1 );
63 ap->error_size += len;
68 static void free_data( struct Arg_parser * const ap )
71 for( i = 0; i < ap->data_size; ++i ) free( ap->data[i].argument );
72 if( ap->data ) { free( ap->data ); ap->data = 0; }
77 static char parse_long_option( struct Arg_parser * const ap,
78 const char * const opt, const char * const arg,
79 const struct ap_Option options[],
84 char exact = 0, ambig = 0;
86 for( len = 0; opt[len+2] && opt[len+2] != '='; ++len ) ;
88 /* Test all long options for either exact match or abbreviated matches. */
89 for( i = 0; options[i].code != 0; ++i )
90 if( options[i].name && strncmp( options[i].name, &opt[2], len ) == 0 )
92 if( strlen( options[i].name ) == len ) /* Exact match found */
93 { index = i; exact = 1; break; }
94 else if( index < 0 ) index = i; /* First nonexact match found */
95 else if( options[index].code != options[i].code ||
96 options[index].has_arg != options[i].has_arg )
97 ambig = 1; /* Second or later nonexact match found */
100 if( ambig && !exact )
102 add_error( ap, "option '" ); add_error( ap, opt );
103 add_error( ap, "' is ambiguous" );
107 if( index < 0 ) /* nothing found */
109 add_error( ap, "unrecognized option '" ); add_error( ap, opt );
110 add_error( ap, "'" );
116 if( opt[len+2] ) /* '--<long_option>=<argument>' syntax */
118 if( options[index].has_arg == ap_no )
120 add_error( ap, "option '--" ); add_error( ap, options[index].name );
121 add_error( ap, "' doesn't allow an argument" );
124 if( options[index].has_arg == ap_yes && !opt[len+3] )
126 add_error( ap, "option '--" ); add_error( ap, options[index].name );
127 add_error( ap, "' requires an argument" );
130 return push_back_record( ap, options[index].code, &opt[len+3] );
133 if( options[index].has_arg == ap_yes )
135 if( !arg || !arg[0] )
137 add_error( ap, "option '--" ); add_error( ap, options[index].name );
138 add_error( ap, "' requires an argument" );
142 return push_back_record( ap, options[index].code, arg );
145 return push_back_record( ap, options[index].code, "" );
149 static char parse_short_option( struct Arg_parser * const ap,
150 const char * const opt, const char * const arg,
151 const struct ap_Option options[],
152 int * const argindp )
154 int cind = 1; /* character index in opt */
159 const unsigned char code = opt[cind];
161 code_str[0] = code; code_str[1] = 0;
164 for( i = 0; options[i].code; ++i )
165 if( code == options[i].code )
166 { index = i; break; }
170 add_error( ap, "invalid option -- '" ); add_error( ap, code_str );
171 add_error( ap, "'" );
175 if( opt[++cind] == 0 ) { ++*argindp; cind = 0; } /* opt finished */
177 if( options[index].has_arg != ap_no && cind > 0 && opt[cind] )
179 if( !push_back_record( ap, code, &opt[cind] ) ) return 0;
180 ++*argindp; cind = 0;
182 else if( options[index].has_arg == ap_yes )
184 if( !arg || !arg[0] )
186 add_error( ap, "option requires an argument -- '" );
187 add_error( ap, code_str ); add_error( ap, "'" );
190 ++*argindp; cind = 0;
191 if( !push_back_record( ap, code, arg ) ) return 0;
193 else if( !push_back_record( ap, code, "" ) ) return 0;
199 char ap_init( struct Arg_parser * const ap,
200 const int argc, const char * const argv[],
201 const struct ap_Option options[], const char in_order )
203 const char ** non_options = 0; /* skipped non-options */
204 int non_options_size = 0; /* number of skipped non-options */
205 int argind = 1; /* index in argv */
212 if( argc < 2 || !argv || !options ) return 1;
214 while( argind < argc )
216 const unsigned char ch1 = argv[argind][0];
217 const unsigned char ch2 = ch1 ? argv[argind][1] : 0;
219 if( ch1 == '-' && ch2 ) /* we found an option */
221 const char * const opt = argv[argind];
222 const char * const arg = ( argind + 1 < argc ) ? argv[argind+1] : 0;
225 if( !argv[argind][2] ) { ++argind; break; } /* we found "--" */
226 else if( !parse_long_option( ap, opt, arg, options, &argind ) ) return 0;
228 else if( !parse_short_option( ap, opt, arg, options, &argind ) ) return 0;
229 if( ap->error ) break;
235 void * tmp = ap_resize_buffer( non_options,
236 ( non_options_size + 1 ) * sizeof *non_options );
238 non_options = (const char **)tmp;
239 non_options[non_options_size++] = argv[argind++];
241 else if( !push_back_record( ap, 0, argv[argind++] ) ) return 0;
244 if( ap->error ) free_data( ap );
247 for( i = 0; i < non_options_size; ++i )
248 if( !push_back_record( ap, 0, non_options[i] ) ) return 0;
249 while( argind < argc )
250 if( !push_back_record( ap, 0, argv[argind++] ) ) return 0;
252 if( non_options ) free( non_options );
257 void ap_free( struct Arg_parser * const ap )
260 if( ap->error ) { free( ap->error ); ap->error = 0; }
265 const char * ap_error( const struct Arg_parser * const ap )
266 { return ap->error; }
269 int ap_arguments( const struct Arg_parser * const ap )
270 { return ap->data_size; }
273 int ap_code( const struct Arg_parser * const ap, const int i )
275 if( i >= 0 && i < ap_arguments( ap ) ) return ap->data[i].code;
280 const char * ap_argument( const struct Arg_parser * const ap, const int i )
282 if( i >= 0 && i < ap_arguments( ap ) ) return ap->data[i].argument;