added gopt
							parent
							
								
									d7c627033b
								
							
						
					
					
						commit
						a9863ecfec
					
				| @ -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