Re: [pacman-dev] [PATCH v3] libmakepkg: add optional argument support to parseopts

2019-11-03 Thread Dave Reisner
On Wed, Oct 23, 2019 at 08:38:08PM -0400, Ethan Sommer wrote:
> Adds a "?" suffix that can be used to indicate that an option's argument is
> optional.
> 
> This allows options to have a default behaviour when the user doesn't
> specify one, e.g.: --color=[when] being able to behave like --color=auto
> when only --color is passed
> 
> Options with optional arguments given on the command line will be returned
> in the form "--opt=optarg" and "-o=optarg". Despite that not being the
> syntax for passing an argument with a shortopt (trying to pass -o=foo
> would make -o's argument "=foo"), this is done to allow the caller to split
> the option and its optarg easily
> 
> Signed-off-by: Ethan Sommer 
> ---
>  scripts/libmakepkg/util/parseopts.sh.in | 116 +++-
>  test/scripts/parseopts_test.sh  |  12 ++-
>  2 files changed, 83 insertions(+), 45 deletions(-)
> 
> diff --git a/scripts/libmakepkg/util/parseopts.sh.in 
> b/scripts/libmakepkg/util/parseopts.sh.in
> index c056cb1e..42540438 100644
> --- a/scripts/libmakepkg/util/parseopts.sh.in
> +++ b/scripts/libmakepkg/util/parseopts.sh.in
> @@ -18,16 +18,23 @@
>  #   along with this program.  If not, see .
>  #
>  # A getopt_long-like parser which portably supports longopts and
> -# shortopts with some GNU extensions. It does not allow for options
> -# with optional arguments. For both short and long opts, options
> -# requiring an argument should be suffixed with a colon. After the
> -# first argument containing the short opts, any number of valid long
> -# opts may be be passed. The end of the options delimiter must then be
> -# added, followed by the user arguments to the calling program.
> +# shortopts with some GNU extensions. For both short and long opts,
> +# options requiring an argument should be suffixed with a colon, and
> +# options with optional arguments should be suffixed with a question
> +# mark. After the first argument containing the short opts, any number
> +# of valid long opts may be be passed. The end of the options delimiter
> +# must then be added, followed by the user arguments to the calling
> +# program.
> +#
> +# Options with optional arguments will be returned as "--longopt=optarg"
> +# for longopts, or "-o=optarg" for shortopts. This isn't actually a valid
> +# way to pass an optional argument with a shortopt on the command line,
> +# but is done by parseopts to enable the caller script to split the option
> +# and its optarg easily.
>  #
>  # Recommended Usage:
> -#   OPT_SHORT='fb:z'
> -#   OPT_LONG=('foo' 'bar:' 'baz')
> +#   OPT_SHORT='fb:zq?'
> +#   OPT_LONG=('foo' 'bar:' 'baz' 'qux?')
>  #   if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then
>  # exit 1
>  #   fi
> @@ -49,29 +56,30 @@ parseopts() {
>   longoptmatch() {
>   local o longmatch=()
>   for o in "${longopts[@]}"; do
> - if [[ ${o%:} = "$1" ]]; then
> + if [[ ${o%[:?]} = "$1" ]]; then
>   longmatch=("$o")
>   break
>   fi
> - [[ ${o%:} = "$1"* ]] && longmatch+=("$o")
> + [[ ${o%[:?]} = "$1"* ]] && longmatch+=("$o")
>   done
>  
>   case ${#longmatch[*]} in
>   1)
> - # success, override with opt and return arg req 
> (0 == none, 1 == required)
> - opt=${longmatch%:}
> - if [[ $longmatch = *: ]]; then
> - return 1
> - else
> - return 0
> - fi ;;
> + # success, override with opt and return arg req 
> (0 == none, 1 == required, 2 == optional)
> + opt=${longmatch%[:?]}
> + case $longmatch in
> + *:)  return 1 ;;
> + *\?) return 2 ;;
> + *)   return 0 ;;
> + esac
> + ;;
>   0)
>   # fail, no match found
>   return 255 ;;
>   *)
>   # fail, ambiguous match
>   printf "${0##*/}: $(gettext "option '%s' is 
> ambiguous; possibilities:")" "--$1"
> - printf " '%s'" "${longmatch[@]%:}"
> + printf " '%s'" "${longmatch[@]%[:?]}"
>   printf '\n'
>   return 254 ;;
>   esac >&2
> @@ -87,32 +95,47 @@ parseopts() {
>   for (( i = 1; i < ${#1}; i++ )); do
>   opt=${1:i:1}
>  
> -  

Re: [pacman-dev] [PATCH v3] libmakepkg: add optional argument support to parseopts

2019-11-03 Thread Ethan Sommer
> Again...  devils advocate.  You give an example of '--colour=auto' being
> equivalent to '--color'.  Why would the default when the options is not
> specified not be default in the codebase?
Fair enough, another example could be if you wanted to allow specifying
a custom log file for whatever reason, one could make -L/--log have an
optional argument to specify what file to output the log to, and if no
argument is given use the default log file that makepkg currently
chooses.
> Why not follow the GNU extension to getopt and use '::' for option
> arguments instead of '?'
The existing code is built around checking for and removing one trailing
character from an option, it'd require both more code change and more
code all-around to deal with checking for the same character either once
or twice than to just check for a different single trailing character.


Re: [pacman-dev] [PATCH v3] libmakepkg: add optional argument support to parseopts

2019-11-01 Thread Allan McRae
On 24/10/19 10:38 am, Ethan Sommer wrote:
> Adds a "?" suffix that can be used to indicate that an option's argument is
> optional.
> 
> This allows options to have a default behaviour when the user doesn't
> specify one, e.g.: --color=[when] being able to behave like --color=auto
> when only --color is passed
> 
> Options with optional arguments given on the command line will be returned
> in the form "--opt=optarg" and "-o=optarg". Despite that not being the
> syntax for passing an argument with a shortopt (trying to pass -o=foo
> would make -o's argument "=foo"), this is done to allow the caller to split
> the option and its optarg easily
> 

Again...  devils advocate.  You give an example of '--colour=auto' being
equivalent to '--color'.  Why would the default when the options is not
specified not be default in the codebase?

Why not follow the GNU extension to getopt and use '::' for option
arguments instead of '?'

Allan


[pacman-dev] [PATCH v3] libmakepkg: add optional argument support to parseopts

2019-10-23 Thread Ethan Sommer
Adds a "?" suffix that can be used to indicate that an option's argument is
optional.

This allows options to have a default behaviour when the user doesn't
specify one, e.g.: --color=[when] being able to behave like --color=auto
when only --color is passed

Options with optional arguments given on the command line will be returned
in the form "--opt=optarg" and "-o=optarg". Despite that not being the
syntax for passing an argument with a shortopt (trying to pass -o=foo
would make -o's argument "=foo"), this is done to allow the caller to split
the option and its optarg easily

Signed-off-by: Ethan Sommer 
---
 scripts/libmakepkg/util/parseopts.sh.in | 116 +++-
 test/scripts/parseopts_test.sh  |  12 ++-
 2 files changed, 83 insertions(+), 45 deletions(-)

diff --git a/scripts/libmakepkg/util/parseopts.sh.in 
b/scripts/libmakepkg/util/parseopts.sh.in
index c056cb1e..42540438 100644
--- a/scripts/libmakepkg/util/parseopts.sh.in
+++ b/scripts/libmakepkg/util/parseopts.sh.in
@@ -18,16 +18,23 @@
 #   along with this program.  If not, see .
 #
 # A getopt_long-like parser which portably supports longopts and
-# shortopts with some GNU extensions. It does not allow for options
-# with optional arguments. For both short and long opts, options
-# requiring an argument should be suffixed with a colon. After the
-# first argument containing the short opts, any number of valid long
-# opts may be be passed. The end of the options delimiter must then be
-# added, followed by the user arguments to the calling program.
+# shortopts with some GNU extensions. For both short and long opts,
+# options requiring an argument should be suffixed with a colon, and
+# options with optional arguments should be suffixed with a question
+# mark. After the first argument containing the short opts, any number
+# of valid long opts may be be passed. The end of the options delimiter
+# must then be added, followed by the user arguments to the calling
+# program.
+#
+# Options with optional arguments will be returned as "--longopt=optarg"
+# for longopts, or "-o=optarg" for shortopts. This isn't actually a valid
+# way to pass an optional argument with a shortopt on the command line,
+# but is done by parseopts to enable the caller script to split the option
+# and its optarg easily.
 #
 # Recommended Usage:
-#   OPT_SHORT='fb:z'
-#   OPT_LONG=('foo' 'bar:' 'baz')
+#   OPT_SHORT='fb:zq?'
+#   OPT_LONG=('foo' 'bar:' 'baz' 'qux?')
 #   if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then
 # exit 1
 #   fi
@@ -49,29 +56,30 @@ parseopts() {
longoptmatch() {
local o longmatch=()
for o in "${longopts[@]}"; do
-   if [[ ${o%:} = "$1" ]]; then
+   if [[ ${o%[:?]} = "$1" ]]; then
longmatch=("$o")
break
fi
-   [[ ${o%:} = "$1"* ]] && longmatch+=("$o")
+   [[ ${o%[:?]} = "$1"* ]] && longmatch+=("$o")
done
 
case ${#longmatch[*]} in
1)
-   # success, override with opt and return arg req 
(0 == none, 1 == required)
-   opt=${longmatch%:}
-   if [[ $longmatch = *: ]]; then
-   return 1
-   else
-   return 0
-   fi ;;
+   # success, override with opt and return arg req 
(0 == none, 1 == required, 2 == optional)
+   opt=${longmatch%[:?]}
+   case $longmatch in
+   *:)  return 1 ;;
+   *\?) return 2 ;;
+   *)   return 0 ;;
+   esac
+   ;;
0)
# fail, no match found
return 255 ;;
*)
# fail, ambiguous match
printf "${0##*/}: $(gettext "option '%s' is 
ambiguous; possibilities:")" "--$1"
-   printf " '%s'" "${longmatch[@]%:}"
+   printf " '%s'" "${longmatch[@]%[:?]}"
printf '\n'
return 254 ;;
esac >&2
@@ -87,32 +95,47 @@ parseopts() {
for (( i = 1; i < ${#1}; i++ )); do
opt=${1:i:1}
 
-   # option doesn't exist
-   if [[ $shortopts != *$opt* ]]; then
-   printf "${0##*/}: $(gettext 
"invalid