added gopt
parent
fe77ac2d00
commit
f0ec4144ed
@ -0,0 +1,265 @@
|
|||||||
|
/* gopt.c version 8.1: tom.viza@gmail.com PUBLIC DOMAIN 2003-8 */
|
||||||
|
/*
|
||||||
|
I, Tom Vajzovic, am the author of this software and its documentation and
|
||||||
|
permanently abandon all copyright and other intellectual property rights in
|
||||||
|
them, including the right to be identified as the author.
|
||||||
|
|
||||||
|
I am fairly certain that this software does what the documentation says it
|
||||||
|
does, but I cannot guarantee that it does, or that it does what you think it
|
||||||
|
should, and I cannot guarantee that it will not have undesirable side effects.
|
||||||
|
|
||||||
|
You are free to use, modify and distribute this software as you please, but
|
||||||
|
you do so at your own risk. If you remove or hide this warning then you are
|
||||||
|
responsible for any problems encountered by people that you make the software
|
||||||
|
available to.
|
||||||
|
|
||||||
|
Before modifying or distributing this software I ask that you would please
|
||||||
|
read http://www.purposeful.co.uk/tfl/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "gopt.h"
|
||||||
|
|
||||||
|
#ifdef USE_SYSEXITS
|
||||||
|
#include <sysexits.h>
|
||||||
|
#else
|
||||||
|
#define EX_OSERR EXIT_FAILURE
|
||||||
|
#define EX_USAGE EXIT_FAILURE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct opt_spec_s {
|
||||||
|
int key;
|
||||||
|
int flags;
|
||||||
|
const char *shorts;
|
||||||
|
const char* const *longs;
|
||||||
|
};
|
||||||
|
typedef struct opt_spec_s opt_spec_t;
|
||||||
|
|
||||||
|
struct opt_s {
|
||||||
|
int key;
|
||||||
|
const char *arg;
|
||||||
|
};
|
||||||
|
typedef struct opt_s opt_t;
|
||||||
|
|
||||||
|
void *gopt_sort( int *argc, const char **argv, const void *opt_specs ){
|
||||||
|
void *opts;
|
||||||
|
{{{
|
||||||
|
const char* const *arg_p= argv + 1;
|
||||||
|
size_t opt_count= 1;
|
||||||
|
for( ; *arg_p; ++arg_p )
|
||||||
|
if( '-' == (*arg_p)[0] && (*arg_p)[1] )
|
||||||
|
if( '-' == (*arg_p)[1] )
|
||||||
|
if( (*arg_p)[2] )
|
||||||
|
++opt_count;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
else {
|
||||||
|
const opt_spec_t *opt_spec_p= opt_specs;
|
||||||
|
for( ; opt_spec_p-> key; ++opt_spec_p )
|
||||||
|
if( strchr( opt_spec_p-> shorts, (*arg_p)[1] )){
|
||||||
|
opt_count+= opt_spec_p-> flags & GOPT_ARG ? 1 : strlen( (*arg_p) + 1 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opts= malloc( opt_count * sizeof(opt_t) );
|
||||||
|
}}}
|
||||||
|
{
|
||||||
|
const char **arg_p= argv + 1;
|
||||||
|
const char **next_operand= arg_p;
|
||||||
|
opt_t *next_option= opts;
|
||||||
|
|
||||||
|
if( ! opts ){
|
||||||
|
perror( argv[0] );
|
||||||
|
exit( EX_OSERR );
|
||||||
|
}
|
||||||
|
for( ; *arg_p; ++arg_p )
|
||||||
|
if( '-' == (*arg_p)[0] && (*arg_p)[1] )
|
||||||
|
if( '-' == (*arg_p)[1] )
|
||||||
|
if( (*arg_p)[2] )
|
||||||
|
{{{
|
||||||
|
const opt_spec_t *opt_spec_p= opt_specs;
|
||||||
|
const char* const *longs= opt_spec_p-> longs;
|
||||||
|
next_option-> key= 0;
|
||||||
|
while( *longs ){
|
||||||
|
const char *option_cp= (*arg_p) + 2;
|
||||||
|
const char *name_cp= *longs;
|
||||||
|
while( *option_cp && *option_cp == *name_cp ){
|
||||||
|
++option_cp;
|
||||||
|
++name_cp;
|
||||||
|
}
|
||||||
|
if( '=' == *option_cp || !*option_cp ){
|
||||||
|
if( *name_cp ){
|
||||||
|
if( next_option-> key ){
|
||||||
|
fprintf( stderr, "%s: --%.*s: abbreviated option is ambiguous\n", argv[0], (int)( option_cp -( (*arg_p) + 2 )), (*arg_p) + 2 );
|
||||||
|
free( opts );
|
||||||
|
exit( EX_USAGE );
|
||||||
|
}
|
||||||
|
next_option-> key= opt_spec_p-> key;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
next_option-> key= opt_spec_p-> key;
|
||||||
|
goto found_long;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( !*++longs ){
|
||||||
|
++opt_spec_p;
|
||||||
|
if( opt_spec_p-> key )
|
||||||
|
longs= opt_spec_p-> longs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( ! next_option-> key ){
|
||||||
|
fprintf( stderr, "%s: --%.*s: unknown option\n", argv[0], (int)strcspn( (*arg_p) + 2, "=" ), (*arg_p) + 2 );
|
||||||
|
free( opts );
|
||||||
|
exit( EX_USAGE );
|
||||||
|
}
|
||||||
|
for( opt_spec_p= opt_specs; opt_spec_p-> key != next_option-> key; ++opt_spec_p );
|
||||||
|
found_long:
|
||||||
|
|
||||||
|
if( !( opt_spec_p-> flags & GOPT_REPEAT )){
|
||||||
|
const opt_t *opt_p= opts;
|
||||||
|
for( ; opt_p != next_option; ++opt_p )
|
||||||
|
if( opt_p-> key == opt_spec_p-> key ){
|
||||||
|
fprintf( stderr, "%s: --%.*s: option may not be repeated (in any long or short form)\n", argv[0], (int)strcspn( (*arg_p) + 2, "=" ), (*arg_p) + 2 );
|
||||||
|
free( opts );
|
||||||
|
exit( EX_USAGE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( opt_spec_p-> flags & GOPT_ARG ){
|
||||||
|
next_option-> arg= strchr( (*arg_p) + 2, '=' ) + 1;
|
||||||
|
if( (char*)0 + 1 == next_option-> arg ){
|
||||||
|
++arg_p;
|
||||||
|
if( !*arg_p || '-' == (*arg_p)[0] && (*arg_p)[1] ){
|
||||||
|
fprintf( stderr, "%s: --%s: option requires an option argument\n", argv[0], (*(arg_p-1)) + 2 );
|
||||||
|
free( opts );
|
||||||
|
exit( EX_USAGE );
|
||||||
|
}
|
||||||
|
next_option-> arg= *arg_p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if( strchr( (*arg_p) + 2, '=' )){
|
||||||
|
fprintf( stderr, "%s: --%.*s: option may not take an option argument\n", argv[0], (int)strcspn( (*arg_p) + 2, "=" ), (*arg_p) + 2 );
|
||||||
|
free( opts );
|
||||||
|
exit( EX_USAGE );
|
||||||
|
}
|
||||||
|
next_option-> arg= NULL;
|
||||||
|
}
|
||||||
|
++next_option;
|
||||||
|
}}}
|
||||||
|
else {
|
||||||
|
for( ++arg_p; *arg_p; ++arg_p )
|
||||||
|
*next_operand++= *arg_p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{{{
|
||||||
|
const char *short_opt= (*arg_p) + 1;
|
||||||
|
for( ;*short_opt; ++short_opt ){
|
||||||
|
const opt_spec_t *opt_spec_p= opt_specs;
|
||||||
|
|
||||||
|
for( ; opt_spec_p-> key; ++opt_spec_p )
|
||||||
|
if( strchr( opt_spec_p-> shorts, *short_opt )){
|
||||||
|
if( !( opt_spec_p-> flags & GOPT_REPEAT )){
|
||||||
|
const opt_t *opt_p= opts;
|
||||||
|
for( ; opt_p != next_option; ++opt_p )
|
||||||
|
if( opt_p-> key == opt_spec_p-> key ){
|
||||||
|
fprintf( stderr, "%s: -%c: option may not be repeated (in any long or short form)\n", argv[0], *short_opt );
|
||||||
|
free( opts );
|
||||||
|
exit( EX_USAGE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next_option-> key= opt_spec_p-> key;
|
||||||
|
|
||||||
|
if( opt_spec_p-> flags & GOPT_ARG ){
|
||||||
|
if( short_opt[1] )
|
||||||
|
next_option-> arg= short_opt + 1;
|
||||||
|
|
||||||
|
else {
|
||||||
|
++arg_p;
|
||||||
|
if( !*arg_p || '-' == (*arg_p)[0] && (*arg_p)[1] ){
|
||||||
|
fprintf( stderr, "%s: -%c: option requires an option argument\n", argv[0], *short_opt );
|
||||||
|
free( opts );
|
||||||
|
exit( EX_USAGE );
|
||||||
|
}
|
||||||
|
next_option-> arg= *arg_p;
|
||||||
|
}
|
||||||
|
++next_option;
|
||||||
|
goto break_2;
|
||||||
|
}
|
||||||
|
next_option-> arg= NULL;
|
||||||
|
++next_option;
|
||||||
|
goto continue_2;
|
||||||
|
}
|
||||||
|
fprintf( stderr, "%s: -%c: unknown option\n", argv[0], *short_opt );
|
||||||
|
free( opts );
|
||||||
|
exit( EX_USAGE );
|
||||||
|
continue_2: 0;
|
||||||
|
}
|
||||||
|
break_2: 0;
|
||||||
|
}}}
|
||||||
|
else
|
||||||
|
*next_operand++= *arg_p;
|
||||||
|
|
||||||
|
next_option-> key= 0;
|
||||||
|
*next_operand= NULL;
|
||||||
|
*argc= next_operand - argv;
|
||||||
|
}
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t gopt( const void *vptr_opts, int key ){
|
||||||
|
const opt_t *opts= vptr_opts;
|
||||||
|
size_t count= 0;
|
||||||
|
for( ; opts-> key; ++opts )
|
||||||
|
count+= opts-> key == key;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t gopt_arg( const void *vptr_opts, int key, const char **arg ){
|
||||||
|
const opt_t *opts= vptr_opts;
|
||||||
|
size_t count= 0;
|
||||||
|
|
||||||
|
for( ; opts-> key; ++opts )
|
||||||
|
if( opts-> key == key ){
|
||||||
|
if( ! count )
|
||||||
|
*arg= opts-> arg;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *gopt_arg_i( const void *vptr_opts, int key, size_t i ){
|
||||||
|
const opt_t *opts= vptr_opts;
|
||||||
|
|
||||||
|
for( ; opts-> key; ++opts )
|
||||||
|
if( opts-> key == key ){
|
||||||
|
if( ! i )
|
||||||
|
return opts-> arg;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t gopt_args( const void *vptr_opts, int key, const char **args, size_t args_len ){
|
||||||
|
const char **args_stop= args + args_len;
|
||||||
|
const char **args_ptr= args;
|
||||||
|
const opt_t *opts= vptr_opts;
|
||||||
|
|
||||||
|
for( ; opts-> key; ++opts )
|
||||||
|
if( opts-> key == key ){
|
||||||
|
if( args_stop == args_ptr )
|
||||||
|
return args_len + gopt( opts, key );
|
||||||
|
|
||||||
|
*args_ptr++= opts-> arg;
|
||||||
|
}
|
||||||
|
if( args_stop != args_ptr )
|
||||||
|
*args_ptr= NULL;
|
||||||
|
return args_ptr - args;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gopt_free( void *vptr_opts ){
|
||||||
|
free( vptr_opts );
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/* gopt.h version 8.1: tom.viza@gmail.com PUBLIC DOMAIN 2003-8 */
|
||||||
|
/*
|
||||||
|
I, Tom Vajzovic, am the author of this software and its documentation and
|
||||||
|
permanently abandon all copyright and other intellectual property rights in
|
||||||
|
them, including the right to be identified as the author.
|
||||||
|
|
||||||
|
I am fairly certain that this software does what the documentation says it
|
||||||
|
does, but I cannot guarantee that it does, or that it does what you think it
|
||||||
|
should, and I cannot guarantee that it will not have undesirable side effects.
|
||||||
|
|
||||||
|
You are free to use, modify and distribute this software as you please, but
|
||||||
|
you do so at your own risk. If you remove or hide this warning then you are
|
||||||
|
responsible for any problems encountered by people that you make the software
|
||||||
|
available to.
|
||||||
|
|
||||||
|
Before modifying or distributing this software I ask that you would please
|
||||||
|
read http://www.purposeful.co.uk/tfl/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GOPT_H_INCLUDED
|
||||||
|
#define GOPT_H_INCLUDED
|
||||||
|
|
||||||
|
#define GOPT_ONCE 0
|
||||||
|
#define GOPT_REPEAT 1
|
||||||
|
#define GOPT_NOARG 0
|
||||||
|
#define GOPT_ARG 2
|
||||||
|
|
||||||
|
#define gopt_start(...) (const void*)( const struct { int k; int f; const char *s; const char*const*l; }[]){ __VA_ARGS__, {0}}
|
||||||
|
#define gopt_option(k,f,s,l) { k, f, s, l }
|
||||||
|
#define gopt_shorts( ... ) (const char*)(const char[]){ __VA_ARGS__, 0 }
|
||||||
|
#define gopt_longs( ... ) (const char**)(const char*[]){ __VA_ARGS__, NULL }
|
||||||
|
|
||||||
|
|
||||||
|
void *gopt_sort( int *argc, const char **argv, const void *opt_specs );
|
||||||
|
/* returns a pointer for use in the following calls
|
||||||
|
* prints to stderr and call exit() on error
|
||||||
|
*/
|
||||||
|
size_t gopt( const void *opts, int key );
|
||||||
|
/* returns the number of times the option was specified
|
||||||
|
* which will be 0 or 1 unless GOPT_REPEAT was used
|
||||||
|
*/
|
||||||
|
size_t gopt_arg( const void *opts, int key, const char **arg );
|
||||||
|
/* returns the number of times the option was specified
|
||||||
|
* writes a pointer to the option argument from the first (or only) occurance to *arg
|
||||||
|
*/
|
||||||
|
const char *gopt_arg_i( const void *opts, int key, size_t i );
|
||||||
|
/* returns a pointer to the ith (starting at zero) occurance
|
||||||
|
* of the option, or NULL if it was not specified that many times
|
||||||
|
*/
|
||||||
|
size_t gopt_args( const void *opts, int key, const char **args, size_t args_len );
|
||||||
|
/* returns the number of times the option was specified
|
||||||
|
* writes pointers to the option arguments in the order of occurance to args[].
|
||||||
|
* writes at most args_len pointers
|
||||||
|
* if the return value is less than args_len, also writes a null pointer
|
||||||
|
*/
|
||||||
|
void gopt_free( void *opts );
|
||||||
|
/* releases memory allocated in the corresponding call to gopt_sort()
|
||||||
|
* opts can no longer be used
|
||||||
|
*/
|
||||||
|
#endif /* GOPT_H_INCLUDED */
|
Loading…
Reference in New Issue