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