From 7a7be6c9a2a89ac5783d4f27d67b0fae3218228f Mon Sep 17 00:00:00 2001 From: Zack Weinberg Date: Sat, 1 Apr 2017 12:11:33 -0400 Subject: getopt: merge from gnulib: function prototype adjustments For standards compliance, getopt, getopt_long, and getopt_long_only in glibc have to take 'char *const *argv' even though they can mutate the array. gnulib has tried to clean this up as much as possible: all the internal functions use 'char **argv', and when used standalone, so do getopt_long and getopt_long_only. Also brought over are __nonnull annotations, corrections to documentation, and apparently it is no longer necessary to worry about conflicting prototypes for getopt. The macroification of the definitions of getopt and __posix_getopt goes beyond what is currently in gnulib. At this point getopt1.c and getopt_int.h are identical to their gnulib versions. * posix/getopt.h: Add backup definition of __nonnull for consistency with gnulib. Define __getopt_argv_const to const if not already defined. (getopt): Update doc comment from gnulib. Prototype unconditionally. Add __nonnull annotation. (__posix_getopt): Add __nonnull annotation. (getopt_long, getopt_long_only): Use __getopt_argv_const in prototypes for consistency with gnulib. Add __nonnull annotations. * posix/getopt.c (_getopt_initialize, _getopt_internal_r) (getopt_internal): Change 'argv' argument to type 'char **'. Remove now-unnecessary casts. (getopt, __posix_getopt): Eliminate repetition with a macro. Cast 'argv' to 'char **' when calling _getopt_internal. * posix/getopt1.c (getopt_long, getopt_long_only): Use __getopt_argv_const for consistency with gnulib. Cast 'argv' to 'char **' when calling _getopt_internal. (_getopt_long_r, _getopt_long_only_r): Change 'argv' argument to type 'char **'. (main): Constify 'long_options'. * posix/getopt_int.h (getopt_internal, _getopt_internal_r) (_getopt_long_r, _getopt_long_only_r): Change 'argv' argument to type 'char **'. --- ChangeLog | 24 +++++++++++++++++++ posix/getopt.c | 49 ++++++++++++++++---------------------- posix/getopt.h | 69 ++++++++++++++++++++++++++++++++++-------------------- posix/getopt1.c | 17 ++++++++------ posix/getopt_int.h | 8 +++---- 5 files changed, 102 insertions(+), 65 deletions(-) diff --git a/ChangeLog b/ChangeLog index d45be5fedd..e2587267b7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,29 @@ 2017-04-07 Zack Weinberg + * posix/getopt.h: Add backup definition of __nonnull for + consistency with gnulib. Define __getopt_argv_const to const + if not already defined. + (getopt): Update doc comment from gnulib. Prototype + unconditionally. Add __nonnull annotation. + (__posix_getopt): Add __nonnull annotation. + (getopt_long, getopt_long_only): Use __getopt_argv_const in + prototypes for consistency with gnulib. Add __nonnull + annotations. + * posix/getopt.c (_getopt_initialize, _getopt_internal_r) + (getopt_internal): Change 'argv' argument to type 'char **'. + Remove now-unnecessary casts. + (getopt, __posix_getopt): Eliminate repetition with a macro. + Cast 'argv' to 'char **' when calling _getopt_internal. + * posix/getopt1.c (getopt_long, getopt_long_only): + Use __getopt_argv_const for consistency with gnulib. + Cast 'argv' to 'char **' when calling _getopt_internal. + (_getopt_long_r, _getopt_long_only_r): + Change 'argv' argument to type 'char **'. + (main): Constify 'long_options'. + * posix/getopt_int.h (getopt_internal, _getopt_internal_r) + (_getopt_long_r, _getopt_long_only_r): + Change 'argv' argument to type 'char **'. + * stdio-common/fxprintf.c (__fxprintf_nocancel): New function. (locked_vfxprintf): New helper function. Handle arbitrary multibyte strings, not just ASCII. diff --git a/posix/getopt.c b/posix/getopt.c index 248fe5b03a..f54bc2d1cf 100644 --- a/posix/getopt.c +++ b/posix/getopt.c @@ -182,7 +182,7 @@ exchange (char **argv, struct _getopt_data *d) /* Initialize the internal data when the first call is made. */ static const char * -_getopt_initialize (int argc, char *const *argv, const char *optstring, +_getopt_initialize (int argc, char **argv, const char *optstring, struct _getopt_data *d, int posixly_correct) { /* Start processing options with ARGV-element 1 (since ARGV-element 0 @@ -272,7 +272,7 @@ _getopt_initialize (int argc, char *const *argv, const char *optstring, long-named options. */ int -_getopt_internal_r (int argc, char *const *argv, const char *optstring, +_getopt_internal_r (int argc, char **argv, const char *optstring, const struct option *longopts, int *longind, int long_only, struct _getopt_data *d, int posixly_correct) { @@ -317,7 +317,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) - exchange ((char **) argv, d); + exchange (argv, d); else if (d->__last_nonopt != d->optind) d->__first_nonopt = d->optind; @@ -340,7 +340,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) - exchange ((char **) argv, d); + exchange (argv, d); else if (d->__first_nonopt == d->__last_nonopt) d->__first_nonopt = d->optind; d->__last_nonopt = argc; @@ -766,7 +766,7 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring, } int -_getopt_internal (int argc, char *const *argv, const char *optstring, +_getopt_internal (int argc, char **argv, const char *optstring, const struct option *longopts, int *longind, int long_only, int posixly_correct) { @@ -786,32 +786,23 @@ _getopt_internal (int argc, char *const *argv, const char *optstring, return result; } -/* glibc gets a LSB-compliant getopt. - Standalone applications get a POSIX-compliant getopt. */ -#if _LIBC -enum { POSIXLY_CORRECT = 0 }; -#else -enum { POSIXLY_CORRECT = 1 }; -#endif - -int -getopt (int argc, char *const *argv, const char *optstring) -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0, POSIXLY_CORRECT); -} +/* glibc gets a LSB-compliant getopt and a POSIX-complaint __posix_getopt. + Standalone applications just get a POSIX-compliant getopt. + POSIX and LSB both require these functions to take 'char *const *argv' + even though this is incorrect (because of the permutation). */ +#define GETOPT_ENTRY(NAME, POSIXLY_CORRECT) \ + int \ + NAME (int argc, char *const *argv, const char *optstring) \ + { \ + return _getopt_internal (argc, (char **)argv, optstring, \ + 0, 0, 0, POSIXLY_CORRECT); \ + } #ifdef _LIBC -int -__posix_getopt (int argc, char *const *argv, const char *optstring) -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0, 1); -} +GETOPT_ENTRY(getopt, 0) +GETOPT_ENTRY(__posix_getopt, 1) +#else +GETOPT_ENTRY(getopt, 1) #endif diff --git a/posix/getopt.h b/posix/getopt.h index c83a186beb..fa6aa6be38 100644 --- a/posix/getopt.h +++ b/posix/getopt.h @@ -33,10 +33,11 @@ # include #endif +#ifndef __GNUC_PREREQ +# define __GNUC_PREREQ(maj, min) (0) +#endif + #ifndef __THROW -# ifndef __GNUC_PREREQ -# define __GNUC_PREREQ(maj, min) (0) -# endif # if defined __cplusplus && __GNUC_PREREQ (2,8) # define __THROW throw () # else @@ -44,6 +45,14 @@ # endif #endif +#ifndef __nonnull +# if __GNUC_PREREQ (3, 3) +# define __nonnull(params) __attribute__ ((__nonnull__ params)) +# else +# define __nonnull(params) +# endif +#endif + #ifdef __cplusplus extern "C" { #endif @@ -139,45 +148,55 @@ struct option scanning, explicitly telling 'getopt' that there are no more options. - If OPTS begins with '--', then non-option arguments are treated as - arguments to the option '\0'. This behavior is specific to the GNU - 'getopt'. */ + If OPTS begins with '-', then non-option arguments are treated as + arguments to the option '\1'. This behavior is specific to the GNU + 'getopt'. If OPTS begins with '+', or POSIXLY_CORRECT is set in + the environment, then do not permute arguments. + + For standards compliance, the 'argv' argument has the type + char *const *, but this is inaccurate; if argument permutation is + enabled, the argv array (not the strings it points to) must be + writable. */ -#ifdef __GNU_LIBRARY__ -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) - __THROW; + __THROW __nonnull ((2, 3)); -# if defined __need_getopt && defined __USE_POSIX2 \ - && !defined __USE_POSIX_IMPLICITLY && !defined __USE_GNU +#if defined __need_getopt && defined __USE_POSIX2 \ + && !defined __USE_POSIX_IMPLICITLY && !defined __USE_GNU /* The GNU getopt has more functionality than the standard version. The additional functionality can be disable at runtime. This redirection helps to also do this at runtime. */ -# ifdef __REDIRECT +# ifdef __REDIRECT extern int __REDIRECT_NTH (getopt, (int ___argc, char *const *___argv, const char *__shortopts), __posix_getopt); -# else +# else extern int __posix_getopt (int ___argc, char *const *___argv, - const char *__shortopts) __THROW; -# define getopt __posix_getopt -# endif + const char *__shortopts) + __THROW __nonnull ((2, 3)); +# define getopt __posix_getopt # endif -#else /* not __GNU_LIBRARY__ */ -extern int getopt (); -#endif /* __GNU_LIBRARY__ */ +#endif #ifndef __need_getopt -extern int getopt_long (int ___argc, char *const *___argv, + +/* The type of the 'argv' argument to getopt_long and getopt_long_only + is properly 'char **', since both functions may write to the array + (in order to move all the options to the beginning). However, for + compatibility with old versions of LSB, glibc has to use 'char *const *' + instead. */ +#ifndef __getopt_argv_const +# define __getopt_argv_const const +#endif + +extern int getopt_long (int ___argc, char *__getopt_argv_const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind) - __THROW; -extern int getopt_long_only (int ___argc, char *const *___argv, + __THROW __nonnull ((2, 3)); +extern int getopt_long_only (int ___argc, char *__getopt_argv_const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind) - __THROW; + __THROW __nonnull ((2, 3)); #endif diff --git a/posix/getopt1.c b/posix/getopt1.c index b4ae6e48f2..b967d24f57 100644 --- a/posix/getopt1.c +++ b/posix/getopt1.c @@ -24,14 +24,15 @@ #include "getopt_int.h" int -getopt_long (int argc, char *const *argv, const char *options, +getopt_long (int argc, char *__getopt_argv_const *argv, const char *options, const struct option *long_options, int *opt_index) { - return _getopt_internal (argc, argv, options, long_options, opt_index, 0, 0); + return _getopt_internal (argc, (char **) argv, options, long_options, + opt_index, 0, 0); } int -_getopt_long_r (int argc, char *const *argv, const char *options, +_getopt_long_r (int argc, char **argv, const char *options, const struct option *long_options, int *opt_index, struct _getopt_data *d) { @@ -45,14 +46,16 @@ _getopt_long_r (int argc, char *const *argv, const char *options, instead. */ int -getopt_long_only (int argc, char *const *argv, const char *options, +getopt_long_only (int argc, char *__getopt_argv_const *argv, + const char *options, const struct option *long_options, int *opt_index) { - return _getopt_internal (argc, argv, options, long_options, opt_index, 1, 0); + return _getopt_internal (argc, (char **) argv, options, long_options, + opt_index, 1, 0); } int -_getopt_long_only_r (int argc, char *const *argv, const char *options, +_getopt_long_only_r (int argc, char **argv, const char *options, const struct option *long_options, int *opt_index, struct _getopt_data *d) { @@ -76,7 +79,7 @@ main (int argc, char **argv) { int this_option_optind = optind ? optind : 1; int option_index = 0; - static struct option long_options[] = + static const struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, diff --git a/posix/getopt_int.h b/posix/getopt_int.h index 9ac03bdaaf..762679a305 100644 --- a/posix/getopt_int.h +++ b/posix/getopt_int.h @@ -21,7 +21,7 @@ #include -extern int _getopt_internal (int ___argc, char *const *___argv, +extern int _getopt_internal (int ___argc, char **___argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only, int __posixly_correct); @@ -101,18 +101,18 @@ struct _getopt_data default values and to clear the initialization flag. */ #define _GETOPT_DATA_INITIALIZER { 1, 1 } -extern int _getopt_internal_r (int ___argc, char *const *___argv, +extern int _getopt_internal_r (int ___argc, char **___argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only, struct _getopt_data *__data, int __posixly_correct); -extern int _getopt_long_r (int ___argc, char *const *___argv, +extern int _getopt_long_r (int ___argc, char **___argv, const char *__shortopts, const struct option *__longopts, int *__longind, struct _getopt_data *__data); -extern int _getopt_long_only_r (int ___argc, char *const *___argv, +extern int _getopt_long_only_r (int ___argc, char **___argv, const char *__shortopts, const struct option *__longopts, int *__longind, -- cgit 1.4.1