[pacman-dev] [PATCH v2] 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

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

diff --git a/scripts/libmakepkg/util/parseopts.sh.in 
b/scripts/libmakepkg/util/parseopts.sh.in
index c056cb1e..9a215648 100644
--- a/scripts/libmakepkg/util/parseopts.sh.in
+++ b/scripts/libmakepkg/util/parseopts.sh.in
@@ -18,16 +18,17 @@
 #   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.
 #
 # 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 +50,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 +89,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 option") -- '%s'\n" "$opt" >&2
-   OPTRET=(--)
-   return 1
-   fi
-
-   OPTRET+=("-$opt")
-   # option requires optarg
-   if [[ $shortopts = *$opt:* ]]; then
-   # if we're not at the end of 
the option chunk, the rest is the optarg
-   if (( i < ${#1} - 1 )); then
-   OPTRET+=(

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

2019-10-23 Thread Dave Reisner
On Wed, Oct 23, 2019 at 06:57:24PM -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
> 
> Signed-off-by: Ethan Sommer 
> ---
>  scripts/libmakepkg/util/parseopts.sh.in | 110 +++-
>  test/scripts/parseopts_test.sh  |  12 ++-
>  2 files changed, 77 insertions(+), 45 deletions(-)
> 
> diff --git a/scripts/libmakepkg/util/parseopts.sh.in 
> b/scripts/libmakepkg/util/parseopts.sh.in
> index c056cb1e..9a215648 100644
> --- a/scripts/libmakepkg/util/parseopts.sh.in
> +++ b/scripts/libmakepkg/util/parseopts.sh.in
> @@ -18,16 +18,17 @@
>  #   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.
>  #
>  # 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 +50,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 +89,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 option") -- '%s'\n" "$opt" >&2
> - OPTRET=(--)
> - return 1
> - fi
> -
> - OPTRET+=("-$opt")
> - # option requires optarg
> - if [[ $shortopts = *$opt:* ]]; then
> - # if we're not at the end of 
> the option ch