[pacman-dev] [PATCH] Added the function parse_options to replace getopt
This will make makepkg work properly on systems like Mac OS X, where the default installed getopt does not handle long options. see also: http://www.archlinux.org/pipermail/pacman-dev/2008-May/011830.html Signed-off-by: Yun Zheng Hu <yunzheng.hu@gmail.com> --- scripts/makepkg.sh.in | 54 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 52 insertions(+), 2 deletions(-) diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index 6dc7db4..ddcb06e 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -27,7 +27,7 @@ # makepkg uses quite a few external programs during its execution. You # need to have at least the following installed for makepkg to function: # awk, bsdtar (libarchive), bzip2, coreutils, fakeroot, find (findutils), -# getopt (util-linux), gettext, grep, gzip, openssl, sed +# gettext, grep, gzip, openssl, sed # gettext initialization export TEXTDOMAIN='pacman' @@ -1117,6 +1117,56 @@ devel_update() { fi } +## +# usage : match_long_opt( $needle, $options ) +# return : matched option +## +match_long_opt() { + local needle=$1; shift + local matches + local item + for item in "$@"; do + [[ "$item" =~ ^"$needle" ]] && matches="$matches $item" + done + matches=($matches) + [ ${#matches[@]} = 1 ] && echo ${matches[0]} +} + +# getopt like parser, returns 1 on error +parse_options() { + local short_options=$1; shift; + local long_options=$1; shift; + local needs_param=0 + until [ -z "$1" ]; do + if [ ${1:0:2} = '--' ]; then + # handle long option + [ "$needs_param" = 1 ] && return 1 + opt=${1:2} + [ -z "$opt" ] && break + longopt=$(match_long_opt $opt ${long_options//,/ }) + [ ! -z "$longopt" ] && printf " %s" "--${longopt}" || return 1 + elif [ ${1:0:1} = '-' ]; then + # handle short option(s) + [ $needs_param = 1 ] && return 1 + opts=${1:1} + local param + local i=0 + while [ $i -lt ${#opts} ]; do + opt=${opts:$((i++)):1} + [[ "$needs_param" = 1 ]] && param="${param}${opt}" && continue + [[ "$short_options" =~ "${opt}" ]] && printf " %s" "-${opt}" || return 1 + [[ "$short_options" =~ "${opt}:" ]] && needs_param=1 + done + [ ! -z "$param" ] && printf " $param" && needs_param=0 + else + # handle non option + [ "$needs_param" = 1 ] && printf " $1" && needs_param=0 + fi + shift + done + printf " --\n" +} + usage() { printf "makepkg (pacman) %s\n" "$myver" echo @@ -1182,7 +1232,7 @@ OPT_LONG="$OPT_LONG,install,log,nocolor,nobuild,rmdeps,repackage,source" OPT_LONG="$OPT_LONG,syncdeps,version,config:" # Pacman Options OPT_LONG="$OPT_LONG,noconfirm,noprogressbar" -OPT_TEMP="$(getopt -o "$OPT_SHORT" -l "$OPT_LONG" -n "$(basename "$0")" -- "$@" || echo 'GETOPT GO BANG!')" +OPT_TEMP="$(parse_options $OPT_SHORT $OPT_LONG "$@" || echo 'GETOPT GO BANG!')" if echo "$OPT_TEMP" | grep -q 'GETOPT GO BANG!'; then # This is a small hack to stop the script bailing with 'set -e' echo; usage; exit 1 # E_INVALID_OPTION; -- 1.5.6.5
Yun Zheng Hu wrote:
This will make makepkg work properly on systems like Mac OS X, where the default installed getopt does not handle long options.
see also: http://www.archlinux.org/pipermail/pacman-dev/2008-May/011830.html
Signed-off-by: Yun Zheng Hu <yunzheng.hu@gmail.com> --- scripts/makepkg.sh.in | 54 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index 6dc7db4..ddcb06e 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -27,7 +27,7 @@ # makepkg uses quite a few external programs during its execution. You # need to have at least the following installed for makepkg to function: # awk, bsdtar (libarchive), bzip2, coreutils, fakeroot, find (findutils), -# getopt (util-linux), gettext, grep, gzip, openssl, sed +# gettext, grep, gzip, openssl, sed
# gettext initialization export TEXTDOMAIN='pacman' @@ -1117,6 +1117,56 @@ devel_update() { fi }
+## +# usage : match_long_opt( $needle, $options ) +# return : matched option +## +match_long_opt() { + local needle=$1; shift + local matches + local item + for item in "$@"; do + [[ "$item" =~ ^"$needle" ]] && matches="$matches $item" + done + matches=($matches) + [ ${#matches[@]} = 1 ] && echo ${matches[0]} +} + +# getopt like parser, returns 1 on error +parse_options() { + local short_options=$1; shift; + local long_options=$1; shift; + local needs_param=0 + until [ -z "$1" ]; do + if [ ${1:0:2} = '--' ]; then + # handle long option + [ "$needs_param" = 1 ] && return 1 + opt=${1:2} + [ -z "$opt" ] && break + longopt=$(match_long_opt $opt ${long_options//,/ }) + [ ! -z "$longopt" ] && printf " %s" "--${longopt}" || return 1 + elif [ ${1:0:1} = '-' ]; then + # handle short option(s) + [ $needs_param = 1 ] && return 1 + opts=${1:1} + local param + local i=0 + while [ $i -lt ${#opts} ]; do + opt=${opts:$((i++)):1} + [[ "$needs_param" = 1 ]] && param="${param}${opt}" && continue + [[ "$short_options" =~ "${opt}" ]] && printf " %s" "-${opt}" || return 1 + [[ "$short_options" =~ "${opt}:" ]] && needs_param=1 + done + [ ! -z "$param" ] && printf " $param" && needs_param=0 + else + # handle non option + [ "$needs_param" = 1 ] && printf " $1" && needs_param=0 + fi + shift + done + printf " --\n" +} + usage() { printf "makepkg (pacman) %s\n" "$myver" echo @@ -1182,7 +1232,7 @@ OPT_LONG="$OPT_LONG,install,log,nocolor,nobuild,rmdeps,repackage,source" OPT_LONG="$OPT_LONG,syncdeps,version,config:" # Pacman Options OPT_LONG="$OPT_LONG,noconfirm,noprogressbar" -OPT_TEMP="$(getopt -o "$OPT_SHORT" -l "$OPT_LONG" -n "$(basename "$0")" -- "$@" || echo 'GETOPT GO BANG!')" +OPT_TEMP="$(parse_options $OPT_SHORT $OPT_LONG "$@" || echo 'GETOPT GO BANG!')" if echo "$OPT_TEMP" | grep -q 'GETOPT GO BANG!'; then # This is a small hack to stop the script bailing with 'set -e' echo; usage; exit 1 # E_INVALID_OPTION;
I need to go through this more fully but this seems OK to me. One comment: you should probably change the GETOPT GO BANG! stuff to something like "PARSE_OPTIONS FAILED", or preferably handle the error return properly. Allan
On Tue, Nov 18, 2008 at 7:46 PM, Allan McRae <allan@archlinux.org> wrote:
Yun Zheng Hu wrote:
This will make makepkg work properly on systems like Mac OS X, where the default installed getopt does not handle long options.
see also: http://www.archlinux.org/pipermail/pacman-dev/2008-May/011830.html
Signed-off-by: Yun Zheng Hu <yunzheng.hu@gmail.com>
I need to go through this more fully but this seems OK to me. One comment: you should probably change the GETOPT GO BANG! stuff to something like "PARSE_OPTIONS FAILED", or preferably handle the error return properly.
Allan- I think I'll trust your judgment on this one, since you have been the makepkg guru. As long as we don't lose functionality, I'm fine with patches like this. When you pull it into your pacman tree, I'll pull it into mine (on maint). -Dan
On Wed, Nov 19, 2008 at 2:46 AM, Allan McRae <allan@archlinux.org> wrote:
I need to go through this more fully but this seems OK to me. One comment: you should probably change the GETOPT GO BANG! stuff to something like "PARSE_OPTIONS FAILED", or preferably handle the error return properly.
Allan
There are still some issues with this patch: - error reporting when an unrecognized option is used or an required argument is not supplied - handling of long options that need parameters/argument. (for example --config) - handling the end of options indicator: -- Proper handling of the error return is quite difficult as it is currently handled by the exit trap. I went for the "PARSE_OPTIONS FAILED" method. I'm sending a new patch which corrects these issues in a few minutes.
participants (3)
-
Allan McRae
-
Dan McGee
-
Yun Zheng Hu