@ -1,4 +1,4 @@
/* $OpenBSD: getopt_long.c,v 1.2 2002/12/03 20:28:12 millert Exp $ */
/* $OpenBSD: getopt_long.c,v 1.3 2002/12/05 21:45:01 millert Exp $ */
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/*-
@ -38,7 +38,7 @@
*/
# if defined(LIBC_SCCS) && !defined(lint)
static char * rcsid = " $OpenBSD: getopt_long.c,v 1.2 2002/12/03 20:28:12 millert Exp $ " ;
static char * rcsid = " $OpenBSD: getopt_long.c,v 1.3 2002/12/05 21:45:01 millert Exp $ " ;
# endif /* LIBC_SCCS and not lint */
# include <err.h>
@ -57,9 +57,9 @@ char *optarg; /* argument associated with option */
# define PRINT_ERROR ((opterr) && (*options != ':'))
# define FLAG_PERMUTE 0x01
# define FLAG_ALLARGS 0x02
# define FLAG_LONGONLY 0x04
# define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
# define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
# define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
# define BADCH (int)'?'
@ -68,9 +68,10 @@ char *optarg; /* argument associated with option */
# define EMSG ""
static int getopt_internal ( int , char * const * , const char * , int ) ;
static int getopt_long_internal ( int , char * const * , const char * ,
const struct option * , int * , int ) ;
static int getopt_internal ( int , char * const * , const char * ,
const struct option * , int * , int ) ;
static int parse_long_options ( int , char * const * , const char * ,
const struct option * , int * , int ) ;
static int gcd ( int , int ) ;
static void permute_args ( int , int , int , char * const * ) ;
@ -92,9 +93,7 @@ static const char illoptstring[] = "unknown option -- %s";
* Compute the greatest common divisor of a and b .
*/
static int
gcd ( a , b )
int a ;
int b ;
gcd ( int a , int b )
{
int c ;
@ -105,7 +104,7 @@ gcd(a, b)
c = a % b ;
}
return b ;
return ( b ) ;
}
/*
@ -114,11 +113,8 @@ gcd(a, b)
* in each block ) .
*/
static void
permute_args ( panonopt_start , panonopt_end , opt_end , nargv )
int panonopt_start ;
int panonopt_end ;
int opt_end ;
char * const * nargv ;
permute_args ( int panonopt_start , int panonopt_end , int opt_end ,
char * const * nargv )
{
int cstart , cyclelen , i , j , ncycle , nnonopts , nopts , pos ;
char * swap ;
@ -148,23 +144,154 @@ permute_args(panonopt_start, panonopt_end, opt_end, nargv)
}
}
/*
* parse_long_options - -
* Parse long options in argc / argv argument vector .
* Returns - 2 if long_only is set and the current option could be a short
* ( single character ) option instead .
*/
static int
parse_long_options ( int nargc , char * const * nargv , const char * options ,
const struct option * long_options , int * idx , int long_only )
{
char * current_argv , * has_equal ;
size_t current_argv_len ;
int i , match ;
current_argv = place ;
match = - 1 ;
optind + + ;
if ( ( has_equal = strchr ( current_argv , ' = ' ) ) ! = NULL ) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv ;
has_equal + + ;
} else
current_argv_len = strlen ( current_argv ) ;
for ( i = 0 ; long_options [ i ] . name ; i + + ) {
/* find matching long option */
if ( strncmp ( current_argv , long_options [ i ] . name ,
current_argv_len ) )
continue ;
if ( strlen ( long_options [ i ] . name ) = = current_argv_len ) {
/* exact match */
match = i ;
break ;
}
/*
* Don ' t try a partial match of a short option when in
* long_only mode . Otherwise there is a potential conflict
* between partial matches and short options .
*/
if ( long_only & & current_argv_len = = 1 )
continue ;
if ( match = = - 1 ) /* partial match */
match = i ;
else {
/* ambiguous abbreviation */
if ( PRINT_ERROR )
warnx ( ambig , ( int ) current_argv_len ,
current_argv ) ;
optopt = 0 ;
return ( BADCH ) ;
}
}
if ( match ! = - 1 ) { /* option found */
if ( long_options [ match ] . has_arg = = no_argument
& & has_equal ) {
if ( PRINT_ERROR )
warnx ( noarg , ( int ) current_argv_len ,
current_argv ) ;
/*
* XXX : GNU sets optopt to val regardless of flag
*/
if ( long_options [ match ] . flag = = NULL )
optopt = long_options [ match ] . val ;
else
optopt = 0 ;
return ( BADARG ) ;
}
if ( long_options [ match ] . has_arg = = required_argument | |
long_options [ match ] . has_arg = = optional_argument ) {
if ( has_equal )
optarg = has_equal ;
else if ( long_options [ match ] . has_arg = =
required_argument ) {
/*
* optional argument doesn ' t use next nargv
*/
optarg = nargv [ optind + + ] ;
}
}
if ( ( long_options [ match ] . has_arg = = required_argument )
& & ( optarg = = NULL ) ) {
/*
* Missing argument ; leading ' : ' indicates no error
* should be generated .
*/
if ( PRINT_ERROR )
warnx ( recargstring ,
current_argv ) ;
/*
* XXX : GNU sets optopt to val regardless of flag
*/
if ( long_options [ match ] . flag = = NULL )
optopt = long_options [ match ] . val ;
else
optopt = 0 ;
- - optind ;
return ( BADARG ) ;
}
} else { /* unknown option */
if ( long_only ) {
- - optind ;
return ( - 2 ) ;
}
if ( PRINT_ERROR )
warnx ( illoptstring , current_argv ) ;
optopt = 0 ;
return ( BADCH ) ;
}
if ( idx )
* idx = match ;
if ( long_options [ match ] . flag ) {
* long_options [ match ] . flag = long_options [ match ] . val ;
return ( 0 ) ;
} else
return ( long_options [ match ] . val ) ;
}
/*
* getopt_internal - -
* Parse argc / argv argument vector . Called by user level routines .
* Returns - 2 if - - is found ( can be long option or end of options marker ) .
*/
static int
getopt_internal ( nargc , nargv , options , flags )
int nargc ;
char * const * nargv ;
const char * options ;
int flags ;
getopt_internal ( int nargc , char * const * nargv , const char * options ,
const struct option * long_options , int * idx , int flags )
{
char * oli ; /* option letter list index */
int optchar ;
static int posixly_correct = - 1 ;
optarg = NULL ;
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a ' + ' .
*/
if ( posixly_correct = = - 1 )
posixly_correct = ( getenv ( " POSIXLY_CORRECT " ) ! = NULL ) ;
if ( posixly_correct | | * options = = ' + ' )
flags & = ~ FLAG_PERMUTE ;
else if ( * options = = ' - ' )
flags | = FLAG_ALLARGS ;
if ( * options = = ' + ' | | * options = = ' - ' )
options + + ;
/*
* XXX Some programs ( like rsyncd ) expect to be able to
* XXX re - initialize optind to 0 and have getopt_long ( 3 )
@ -194,7 +321,7 @@ start:
optind = nonopt_start ;
}
nonopt_start = nonopt_end = - 1 ;
return - 1 ;
return ( - 1 ) ;
}
if ( ( * ( place = nargv [ optind ] ) ! = ' - ' )
| | ( place [ 1 ] = = ' \0 ' ) ) { /* found non-option */
@ -205,14 +332,14 @@ start:
* return non - option as argument to option 1
*/
optarg = nargv [ optind + + ] ;
return INORDER ;
return ( INORDER ) ;
}
if ( ! ( flags & FLAG_PERMUTE ) ) {
/*
* If no permutation wanted , stop parsing
* at first non - option .
*/
return - 1 ;
return ( - 1 ) ;
}
/* do permutation */
if ( nonopt_start = = - 1 )
@ -230,42 +357,64 @@ start:
}
if ( nonopt_start ! = - 1 & & nonopt_end = = - 1 )
nonopt_end = optind ;
if ( place [ 1 ] & & * + + place = = ' - ' ) { /* found "--" */
place + + ;
return - 2 ;
if ( strcmp ( place , " -- " ) = = 0 ) {
optind + + ;
place = EMSG ;
/*
* We found an option ( - - ) , so if we skipped
* non - options , we have to permute .
*/
if ( nonopt_end ! = - 1 ) {
permute_args ( nonopt_start , nonopt_end ,
optind , nargv ) ;
optind - = nonopt_end - nonopt_start ;
}
nonopt_start = nonopt_end = - 1 ;
return ( - 1 ) ;
}
place + + ;
/* Check long options if we have any */
if ( long_options ! = NULL ) {
int long_only = 0 ;
if ( * place = = ' - ' | |
( long_only = ( flags & FLAG_LONGONLY ) ) ) {
if ( ! long_only )
place + + ;
optchar = parse_long_options ( nargc , nargv ,
options , long_options , idx , long_only ) ;
if ( optchar ! = - 2 ) {
place = EMSG ;
return ( optchar ) ;
}
}
}
}
if ( ( optchar = ( int ) * place + + ) = = ( int ) ' : ' | |
( oli = strchr ( options , optchar ) ) = = NULL ) {
/* could it be a long option with a single '-'? */
if ( flags & FLAG_LONGONLY )
return - 2 ;
/* option letter unknown or ':' */
if ( ! * place )
+ + optind ;
if ( PRINT_ERROR )
warnx ( illoptchar , optchar ) ;
optopt = optchar ;
return BADCH ;
return ( BADCH ) ;
}
if ( optchar = = ' W ' & & oli [ 1 ] = = ' ; ' ) { /* -W long-option */
/* XXX: what if no long options provided (called by getopt)? */
if ( * place )
return - 2 ;
if ( long_options ! = NULL & & optchar = = ' W ' & & oli [ 1 ] = = ' ; ' ) {
/* -W long-option */
if ( + + optind > = nargc ) { /* no arg */
place = EMSG ;
if ( PRINT_ERROR )
warnx ( recargchar , optchar ) ;
optopt = optchar ;
return BADARG ;
return ( BADARG ) ;
} else /* white space */
place = nargv [ optind ] ;
/*
* Handle - W arg the same as - - arg ( which causes getopt to
* stop parsing ) .
*/
return - 2 ;
optchar = parse_long_options ( nargc , nargv , options ,
long_options , idx , 0 ) ;
place = EMSG ;
return ( optchar ) ;
}
if ( * + + oli ! = ' : ' ) { /* doesn't take argument */
if ( ! * place )
@ -281,7 +430,7 @@ start:
if ( PRINT_ERROR )
warnx ( recargchar , optchar ) ;
optopt = optchar ;
return BADARG ;
return ( BADARG ) ;
} else
optarg = nargv [ optind ] ;
}
@ -289,7 +438,7 @@ start:
+ + optind ;
}
/* dump back option letter */
return optchar ;
return ( optchar ) ;
}
# ifdef REPLACE_GETOPT
@ -300,183 +449,20 @@ start:
* [ eventually this will replace the BSD getopt ]
*/
int
getopt ( nargc , nargv , options )
int nargc ;
char * const * nargv ;
const char * options ;
getopt ( int nargc , char * const * nargv , const char * options )
{
int retval ;
if ( ( retval = getopt_internal ( nargc , nargv , options , 0 ) ) = = - 2 ) {
+ + optind ;
/*
* We found an option ( - - ) , so if we skipped non - options ,
* we have to permute .
*/
if ( nonopt_end ! = - 1 ) {
permute_args ( nonopt_start , nonopt_end , optind ,
nargv ) ;
optind - = nonopt_end - nonopt_start ;
}
nonopt_start = nonopt_end = - 1 ;
retval = - 1 ;
}
return retval ;
}
# endif /* REPLACE_GETOPT */
/*
* getopt_long_internal - -
* Parse argc / argv argument vector .
*/
static int
getopt_long_internal ( nargc , nargv , options , long_options , idx , flags )
int nargc ;
char * const * nargv ;
const char * options ;
const struct option * long_options ;
int * idx ;
int flags ;
{
int retval ;
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a ' + ' .
* We dont ' pass FLAG_PERMUTE to getopt_internal ( ) since
* the BSD getopt ( 3 ) ( unlike GNU ) has never done this .
*
* Furthermore , since many privileged programs call getopt ( )
* before dropping privileges it makes sense to keep things
* as simple ( and bug - free ) as possible .
*/
if ( getenv ( " POSIXLY_CORRECT " ) ) {
if ( * options = = ' + ' | | * options = = ' - ' )
options + + ;
} else {
if ( * options = = ' + ' ) {
options + + ;
} else {
flags | = FLAG_PERMUTE ;
if ( * options = = ' - ' ) {
flags | = FLAG_ALLARGS ;
options + + ;
}
}
}
if ( ( retval = getopt_internal ( nargc , nargv , options , flags ) ) = = - 2 ) {
char * current_argv , * has_equal ;
size_t current_argv_len ;
int i , match ;
current_argv = place ;
match = - 1 ;
optind + + ;
place = EMSG ;
if ( * current_argv = = ' \0 ' ) { /* found "--" */
/*
* We found an option ( - - ) , so if we skipped
* non - options , we have to permute .
*/
if ( nonopt_end ! = - 1 ) {
permute_args ( nonopt_start , nonopt_end ,
optind , nargv ) ;
optind - = nonopt_end - nonopt_start ;
}
nonopt_start = nonopt_end = - 1 ;
return - 1 ;
}
if ( ( has_equal = strchr ( current_argv , ' = ' ) ) ! = NULL ) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv ;
has_equal + + ;
} else
current_argv_len = strlen ( current_argv ) ;
for ( i = 0 ; long_options [ i ] . name ; i + + ) {
/* find matching long option */
if ( strncmp ( current_argv , long_options [ i ] . name ,
current_argv_len ) )
continue ;
if ( strlen ( long_options [ i ] . name ) = =
( unsigned ) current_argv_len ) {
/* exact match */
match = i ;
break ;
}
if ( match = = - 1 ) /* partial match */
match = i ;
else {
/* ambiguous abbreviation */
if ( PRINT_ERROR )
warnx ( ambig , ( int ) current_argv_len ,
current_argv ) ;
optopt = 0 ;
return BADCH ;
}
}
if ( match ! = - 1 ) { /* option found */
if ( long_options [ match ] . has_arg = = no_argument
& & has_equal ) {
if ( PRINT_ERROR )
warnx ( noarg , ( int ) current_argv_len ,
current_argv ) ;
/*
* XXX : GNU sets optopt to val regardless of
* flag
*/
if ( long_options [ match ] . flag = = NULL )
optopt = long_options [ match ] . val ;
else
optopt = 0 ;
return BADARG ;
}
if ( long_options [ match ] . has_arg = = required_argument | |
long_options [ match ] . has_arg = = optional_argument ) {
if ( has_equal )
optarg = has_equal ;
else if ( long_options [ match ] . has_arg = =
required_argument ) {
/*
* optional argument doesn ' t use
* next nargv
*/
optarg = nargv [ optind + + ] ;
}
}
if ( ( long_options [ match ] . has_arg = = required_argument )
& & ( optarg = = NULL ) ) {
/*
* Missing argument ; leading ' : '
* indicates no error should be generated
*/
if ( PRINT_ERROR )
warnx ( recargstring , current_argv ) ;
/*
* XXX : GNU sets optopt to val regardless
* of flag
*/
if ( long_options [ match ] . flag = = NULL )
optopt = long_options [ match ] . val ;
else
optopt = 0 ;
- - optind ;
return BADARG ;
}
} else { /* unknown option */
if ( PRINT_ERROR )
warnx ( illoptstring , current_argv ) ;
optopt = 0 ;
return BADCH ;
}
if ( long_options [ match ] . flag ) {
* long_options [ match ] . flag = long_options [ match ] . val ;
retval = 0 ;
} else
retval = long_options [ match ] . val ;
if ( idx )
* idx = match ;
}
return retval ;
return ( getopt_internal ( nargc , nargv , options , NULL , NULL , 0 ) ) ;
}
# endif /* REPLACE_GETOPT */
/*
* getopt_long - -
@ -491,7 +477,8 @@ getopt_long(nargc, nargv, options, long_options, idx)
int * idx ;
{
return getopt_long_internal ( nargc , nargv , options , long_options , idx , 0 ) ;
return ( getopt_internal ( nargc , nargv , options , long_options , idx ,
FLAG_PERMUTE ) ) ;
}
/*
@ -507,6 +494,6 @@ getopt_long_only(nargc, nargv, options, long_options, idx)
int * idx ;
{
return getopt_long _internal ( nargc , nargv , options , long_options , idx ,
FLAG_LONGONLY ) ;
return ( getopt_internal ( nargc , nargv , options , long_options , idx ,
FLAG_PERMUTE | FLAG_ LONGONLY ) ) ;
}